diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb index 044bab74d..61cd43674 100644 --- a/app/controllers/organisations_controller.rb +++ b/app/controllers/organisations_controller.rb @@ -44,6 +44,12 @@ class OrganisationsController < ApplicationController redirect_to schemes_csv_confirmation_organisation_path end + def duplicate_schemes + authorize @organisation + + get_duplicate_schemes_and_locations + end + def show redirect_to details_organisation_path(@organisation) end @@ -295,6 +301,22 @@ class OrganisationsController < ApplicationController render json: org_data.to_json end + def confirm_duplicate_schemes + authorize @organisation + + if scheme_duplicates_checked_params[:scheme_duplicates_checked] == "true" + @organisation.schemes_deduplicated_at = Time.zone.now + if @organisation.save + flash[:notice] = I18n.t("organisation.duplicate_schemes_confirmed") + redirect_to schemes_organisation_path(@organisation) + end + else + @organisation.errors.add(:scheme_duplicates_checked, I18n.t("validations.organisation.scheme_duplicates_not_resolved")) + get_duplicate_schemes_and_locations + render :duplicate_schemes, status: :unprocessable_entity + end + end + private def filter_type @@ -325,6 +347,10 @@ private params.require(:organisation).permit(rent_periods: [], all_rent_periods: []) end + def scheme_duplicates_checked_params + params.require(:organisation).permit(:scheme_duplicates_checked) + end + def codes_only_export? params.require(:codes_only) == "true" end @@ -344,4 +370,18 @@ private def find_resource @organisation = Organisation.find(params[:id]) end + + def get_duplicate_schemes_and_locations + duplicate_scheme_sets = @organisation.owned_schemes.duplicate_sets + @duplicate_schemes = duplicate_scheme_sets.map { |set| set.map { |id| @organisation.owned_schemes.find(id) } } + @duplicate_locations = [] + @organisation.owned_schemes.each do |scheme| + duplicate_location_sets = scheme.locations.duplicate_sets + next unless duplicate_location_sets.any? + + duplicate_location_sets.each do |duplicate_set| + @duplicate_locations << { scheme: scheme, locations: duplicate_set.map { |id| scheme.locations.find(id) } } + end + end + end end diff --git a/app/controllers/start_controller.rb b/app/controllers/start_controller.rb index f3f793a17..dd4232b7b 100644 --- a/app/controllers/start_controller.rb +++ b/app/controllers/start_controller.rb @@ -1,4 +1,6 @@ class StartController < ApplicationController + include CollectionResourcesHelper + def index if current_user @homepage_presenter = HomepagePresenter.new(current_user) @@ -7,114 +9,67 @@ class StartController < ApplicationController end def download_24_25_sales_form - send_file( - Rails.root.join("public/files/2024_25_sales_paper_form.pdf"), - filename: "2024-25 Sales paper form.pdf", - type: "application/pdf", - ) + download_resource("2024_25_sales_paper_form.pdf", "2024-25 Sales paper form.pdf") end def download_23_24_sales_form - send_file( - Rails.root.join("public/files/2023_24_sales_paper_form.pdf"), - filename: "2023-24 Sales paper form.pdf", - type: "application/pdf", - ) + download_resource("2023_24_sales_paper_form.pdf", "2023-24 Sales paper form.pdf") end def download_24_25_lettings_form - send_file( - Rails.root.join("public/files/2024_25_lettings_paper_form.pdf"), - filename: "2024-25 Lettings paper form.pdf", - type: "application/pdf", - ) + download_resource("2024_25_lettings_paper_form.pdf", "2024-25 Lettings paper form.pdf") end def download_23_24_lettings_form - send_file( - Rails.root.join("public/files/2023_24_lettings_paper_form.pdf"), - filename: "2023-24 Lettings paper form.pdf", - type: "application/pdf", - ) + download_resource("2023_24_lettings_paper_form.pdf", "2023-24 Lettings paper form.pdf") end def download_24_25_lettings_bulk_upload_template - send_file( - Rails.root.join("public/files/bulk-upload-lettings-template-2024-25.xlsx"), - filename: "2024-25-lettings-bulk-upload-template.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-lettings-template-2024-25.xlsx", "2024-25-lettings-bulk-upload-template.xlsx") end def download_24_25_lettings_bulk_upload_specification - send_file( - Rails.root.join("public/files/bulk-upload-lettings-specification-2024-25.xlsx"), - filename: "2024-25-lettings-bulk-upload-specification.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-lettings-specification-2024-25.xlsx", "2024-25-lettings-bulk-upload-specification.xlsx") end def download_24_25_sales_bulk_upload_template - send_file( - Rails.root.join("public/files/bulk-upload-sales-template-2024-25.xlsx"), - filename: "2024-25-sales-bulk-upload-template.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-sales-template-2024-25.xlsx", "2024-25-sales-bulk-upload-template.xlsx") end def download_24_25_sales_bulk_upload_specification - send_file( - Rails.root.join("public/files/bulk-upload-sales-specification-2024-25.xlsx"), - filename: "2024-25-sales-bulk-upload-specification.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-sales-specification-2024-25.xlsx", "2024-25-sales-bulk-upload-specification.xlsx") end def download_23_24_lettings_bulk_upload_template - send_file( - Rails.root.join("public/files/bulk-upload-lettings-template-2023-24.xlsx"), - filename: "2023-24-lettings-bulk-upload-template.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-lettings-template-2023-24.xlsx", "2023-24-lettings-bulk-upload-template.xlsx") end def download_23_24_lettings_bulk_upload_legacy_template - send_file( - Rails.root.join("public/files/bulk-upload-lettings-legacy-template-2023-24.xlsx"), - filename: "2023-24-lettings-bulk-upload-legacy-template.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-lettings-legacy-template-2023-24.xlsx", "2023-24-lettings-bulk-upload-legacy-template.xlsx") end def download_23_24_lettings_bulk_upload_specification - send_file( - Rails.root.join("public/files/bulk-upload-lettings-specification-2023-24.xlsx"), - filename: "2023-24-lettings-bulk-upload-specification.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-lettings-specification-2023-24.xlsx", "2023-24-lettings-bulk-upload-specification.xlsx") end def download_23_24_sales_bulk_upload_template - send_file( - Rails.root.join("public/files/bulk-upload-sales-template-2023-24.xlsx"), - filename: "2023-24-sales-bulk-upload-template.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-sales-template-2023-24.xlsx", "2023-24-sales-bulk-upload-template.xlsx") end def download_23_24_sales_bulk_upload_legacy_template - send_file( - Rails.root.join("public/files/bulk-upload-sales-legacy-template-2023-24.xlsx"), - filename: "2023-24-sales-bulk-upload-legacy-template.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-sales-legacy-template-2023-24.xlsx", "2023-24-sales-bulk-upload-legacy-template.xlsx") end def download_23_24_sales_bulk_upload_specification - send_file( - Rails.root.join("public/files/bulk-upload-sales-specification-2023-24.xlsx"), - filename: "2023-24-sales-bulk-upload-specification.xlsx", - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + download_resource("bulk-upload-sales-specification-2023-24.xlsx", "2023-24-sales-bulk-upload-specification.xlsx") + end + +private + + def download_resource(filename, download_filename) + file = CollectionResourcesService.new.get_file(filename) + return render_not_found unless file + + send_data(file, disposition: "attachment", filename: download_filename) end end diff --git a/app/helpers/collection_resources_helper.rb b/app/helpers/collection_resources_helper.rb index a85670bda..5ab539cde 100644 --- a/app/helpers/collection_resources_helper.rb +++ b/app/helpers/collection_resources_helper.rb @@ -1,15 +1,22 @@ module CollectionResourcesHelper + HUMAN_READABLE_CONTENT_TYPE = { "application/pdf": "PDF", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "Microsoft Excel", + "application/vnd.ms-excel": "Microsoft Excel (Old Format)", + "application/msword": "Microsoft Word", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "Microsoft Word (DOCX)", + "image/jpeg": "JPEG Image", + "image/png": "PNG Image", + "text/plain": "Text Document", + "text/html": "HTML Document" }.freeze + def file_type_size_and_pages(file, number_of_pages: nil) - extension_mapping = { - "xlsx" => "Microsoft Excel", - "pdf" => "PDF", - } - extension = File.extname(file)[1..] + file_pages = number_of_pages ? pluralize(number_of_pages, "page") : nil + metadata = CollectionResourcesService.new.get_file_metadata(file) - file_type = extension_mapping.fetch(extension, extension) + return [file_pages].compact.join(", ") unless metadata - file_size = number_to_human_size(File.size("public/files/#{file}"), precision: 0, significant: false) - file_pages = number_of_pages ? pluralize(number_of_pages, "page") : nil + file_size = number_to_human_size(metadata["content_length"].to_i) + file_type = HUMAN_READABLE_CONTENT_TYPE[metadata["content_type"].to_sym] || "Unknown File Type" [file_type, file_size, file_pages].compact.join(", ") end end diff --git a/app/helpers/schemes_helper.rb b/app/helpers/schemes_helper.rb index 0e318d283..7efb9fffd 100644 --- a/app/helpers/schemes_helper.rb +++ b/app/helpers/schemes_helper.rb @@ -85,6 +85,14 @@ module SchemesHelper end end + def display_duplicate_schemes_banner?(organisation, current_user) + return unless organisation.absorbed_organisations.merged_during_open_collection_period.any? + return unless current_user.data_coordinator? || current_user.support? + return if organisation.schemes_deduplicated_at.present? && organisation.schemes_deduplicated_at > organisation.absorbed_organisations.map(&:merge_date).max + + organisation.owned_schemes.duplicate_sets.any? || organisation.owned_schemes.any? { |scheme| scheme.locations.duplicate_sets.any? } + end + private ActivePeriod = Struct.new(:from, :to) diff --git a/app/models/forms/bulk_upload_lettings/prepare_your_file.rb b/app/models/forms/bulk_upload_lettings/prepare_your_file.rb index 159436ce1..984451dbb 100644 --- a/app/models/forms/bulk_upload_lettings/prepare_your_file.rb +++ b/app/models/forms/bulk_upload_lettings/prepare_your_file.rb @@ -35,25 +35,25 @@ module Forms def legacy_template_path case year when 2023 - "/files/bulk-upload-lettings-legacy-template-2023-24.xlsx" + download_23_24_lettings_bulk_upload_legacy_template_path end end def template_path case year when 2023 - "/files/bulk-upload-lettings-template-2023-24.xlsx" + download_23_24_lettings_bulk_upload_template_path when 2024 - "/files/bulk-upload-lettings-template-2024-25.xlsx" + download_24_25_lettings_bulk_upload_template_path end end def specification_path case year when 2023 - "/files/bulk-upload-lettings-specification-2023-24.xlsx" + download_23_24_lettings_bulk_upload_specification_path when 2024 - "/files/bulk-upload-lettings-specification-2024-25.xlsx" + download_24_25_lettings_bulk_upload_specification_path end end diff --git a/app/models/forms/bulk_upload_sales/prepare_your_file.rb b/app/models/forms/bulk_upload_sales/prepare_your_file.rb index 4bf0797a8..d6d5276c2 100644 --- a/app/models/forms/bulk_upload_sales/prepare_your_file.rb +++ b/app/models/forms/bulk_upload_sales/prepare_your_file.rb @@ -34,25 +34,25 @@ module Forms def legacy_template_path case year when 2023 - "/files/bulk-upload-sales-legacy-template-2023-24.xlsx" + download_23_24_sales_bulk_upload_legacy_template_path end end def template_path case year when 2023 - "/files/bulk-upload-sales-template-2023-24.xlsx" + download_23_24_sales_bulk_upload_template_path when 2024 - "/files/bulk-upload-sales-template-2024-25.xlsx" + download_24_25_sales_bulk_upload_template_path end end def specification_path case year when 2023 - "/files/bulk-upload-sales-specification-2023-24.xlsx" + download_23_24_sales_bulk_upload_specification_path when 2024 - "/files/bulk-upload-sales-specification-2024-25.xlsx" + download_24_25_sales_bulk_upload_specification_path end end diff --git a/app/policies/organisation_policy.rb b/app/policies/organisation_policy.rb index 9c27d6e91..9c5fc4449 100644 --- a/app/policies/organisation_policy.rb +++ b/app/policies/organisation_policy.rb @@ -34,4 +34,12 @@ class OrganisationPolicy editable_sales_logs = organisation.sales_logs.visible.after_date(editable_from_date) organisation.sales_logs.visible.where(saledate: nil).any? || editable_sales_logs.any? end + + def duplicate_schemes? + user.support? || (user.data_coordinator? && user.organisation == organisation) + end + + def confirm_duplicate_schemes? + duplicate_schemes? + end end diff --git a/app/services/bulk_upload/sales/validator.rb b/app/services/bulk_upload/sales/validator.rb index 777424349..a473a6461 100644 --- a/app/services/bulk_upload/sales/validator.rb +++ b/app/services/bulk_upload/sales/validator.rb @@ -43,12 +43,12 @@ class BulkUpload::Sales::Validator return false if any_setup_errors? if row_parsers.any?(&:block_log_creation?) - Sentry.capture_exception("Bulk upload log creation blocked: #{bulk_upload.id}.") + Sentry.capture_message("Bulk upload log creation blocked: #{bulk_upload.id}.") return false end if any_logs_already_exist? && FeatureToggle.bulk_upload_duplicate_log_check_enabled? - Sentry.capture_exception("Bulk upload log creation blocked due to duplicate logs: #{bulk_upload.id}.") + Sentry.capture_message("Bulk upload log creation blocked due to duplicate logs: #{bulk_upload.id}.") return false end @@ -57,7 +57,7 @@ class BulkUpload::Sales::Validator end if any_logs_invalid? - Sentry.capture_exception("Bulk upload log creation blocked due to invalid logs after blanking non setup fields: #{bulk_upload.id}.") + Sentry.capture_message("Bulk upload log creation blocked due to invalid logs after blanking non setup fields: #{bulk_upload.id}.") return false end diff --git a/app/services/collection_resources_service.rb b/app/services/collection_resources_service.rb new file mode 100644 index 000000000..50e1fc59a --- /dev/null +++ b/app/services/collection_resources_service.rb @@ -0,0 +1,21 @@ +class CollectionResourcesService + def initialize + @storage_service = if FeatureToggle.local_storage? + Storage::LocalDiskService.new + else + Storage::S3Service.new(Configuration::EnvConfigurationService.new, ENV["COLLECTION_RESOURCES_BUCKET"]) + end + end + + def get_file(file) + @storage_service.get_file_io(file) + rescue StandardError + nil + end + + def get_file_metadata(file) + @storage_service.get_file_metadata(file) + rescue StandardError + nil + end +end diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb index 91989ff86..f63eceaef 100644 --- a/app/services/feature_toggle.rb +++ b/app/services/feature_toggle.rb @@ -34,4 +34,8 @@ class FeatureToggle def self.delete_user_enabled? true end + + def self.local_storage? + Rails.env.development? + end end diff --git a/app/services/storage/local_disk_service.rb b/app/services/storage/local_disk_service.rb index f0cc358d1..cd99d3d48 100644 --- a/app/services/storage/local_disk_service.rb +++ b/app/services/storage/local_disk_service.rb @@ -22,5 +22,14 @@ module Storage f.write data end end + + def get_file_metadata(filename) + path = Rails.root.join("tmp/storage", filename) + + { + "content_length" => File.size(path), + "content_type" => MiniMime.lookup_by_filename(path.to_s)&.content_type || "application/octet-stream", + } + end end end diff --git a/app/services/storage/s3_service.rb b/app/services/storage/s3_service.rb index 3592eaa67..0cd4a1f20 100644 --- a/app/services/storage/s3_service.rb +++ b/app/services/storage/s3_service.rb @@ -39,6 +39,10 @@ module Storage ) end + def get_file_metadata(file_name) + @client.head_object(bucket: @configuration.bucket_name, key: file_name) + end + private def create_configuration diff --git a/app/views/organisations/duplicate_schemes.html.erb b/app/views/organisations/duplicate_schemes.html.erb new file mode 100644 index 000000000..427cf427c --- /dev/null +++ b/app/views/organisations/duplicate_schemes.html.erb @@ -0,0 +1,138 @@ +<% content_for :before_content do %> + <%= govuk_back_link href: schemes_organisation_path(@organisation) %> +<% end %> +<%= form_with model: @organisation, url: schemes_duplicates_organisation_path(@organisation), method: "post" do |f| %> + <%= f.govuk_error_summary %> + + <% if @duplicate_schemes.any? %> + <% if @duplicate_locations.any? %> + <% title = "Review these sets of schemes and locations" %> + <% else %> + <% title = "Review these sets of schemes" %> + <% end %> + <% else %> + <% title = "Review these sets of locations" %> + <% end %> + + <% content_for :title, title %> + + <% if current_user.support? %> + <%= render SubNavigationComponent.new( + items: secondary_items(request.path, @organisation.id), + ) %> + <% end %> + +
+
+

<%= title %>

+ +

Since your organisation recently merged, we’ve reviewed your schemes for possible duplicates.

+

These sets of schemes and locations might be duplicates because they have the same answers for certain fields.

+

What you need to do

+ +

If you need help with this, <%= govuk_link_to "contact the helpdesk (opens in a new tab)", GlobalConstants::HELPDESK_URL, target: "#" %>.

+ + <% if @duplicate_schemes.any? %> +

<%= @duplicate_schemes.count == 1 ? "This set" : "These #{@duplicate_schemes.count} sets" %> of schemes might have duplicates

+ + <%= govuk_details(summary_text: "Why are these schemes identified as duplicates?") do %> +

+ These schemes have the same answers for the following fields: +

+ + <% end %> + + <%= govuk_table do |table| %> + <%= table.with_head do |head| %> + <% head.with_row do |row| %> + <% row.with_cell(header: true, text: "Schemes") %> + <% end %> + + <%= table.with_body do |body| %> + <% @duplicate_schemes.each do |duplicate_set| %> + <% body.with_row do |row| %> + <% row.with_cell do %> +
    + <% duplicate_set.each do |scheme| %> +
  1. + <%= govuk_link_to scheme.service_name, scheme %> +
  2. + <% end %> +
+ <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + + <% if @duplicate_locations.any? %> +

<%= @duplicate_locations.count == 1 ? "This set" : "These #{@duplicate_locations.count} sets" %> of locations might have duplicates

+ <%= govuk_details(summary_text: "Why are these locations identified as duplicates?") do %> +

+ These locations belong to the same scheme and have the same answers for the following fields: +

+ + <% end %> + + <%= govuk_table do |table| %> + <%= table.with_head do |head| %> + <% head.with_row do |row| %> + <% row.with_cell(header: true, text: "Locations") %> + <% row.with_cell(header: true, text: "Scheme") %> + <% end %> + + <%= table.with_body do |body| %> + <% @duplicate_locations.each do |duplicate_set| %> + <% body.with_row do |row| %> + <% row.with_cell do %> +
    + <% duplicate_set[:locations].each do |location| %> +
  1. + <%= govuk_link_to location.name, scheme_location_path(location) %> +
  2. + <% end %> +
+ <% end %> + <% row.with_cell do %> + <%= govuk_link_to duplicate_set[:scheme].service_name, duplicate_set[:scheme] %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + + <%= f.govuk_check_boxes_fieldset :scheme_duplicates_checked, + legend: { text: "Have you resolved all duplicates?" } do %> + <%= f.govuk_check_box :scheme_duplicates_checked, + true, + false, + multiple: false, + checked: false, + label: { text: "Yes, none of the schemes and locations above are duplicates" } %> + <% end %> + + <%= f.govuk_submit "Confirm" %> +
+
+<% end %> diff --git a/app/views/organisations/schemes.html.erb b/app/views/organisations/schemes.html.erb index 58b16243a..b9706d4db 100644 --- a/app/views/organisations/schemes.html.erb +++ b/app/views/organisations/schemes.html.erb @@ -11,6 +11,16 @@ ) %>

Supported housing schemes

<% end %> + +<% if display_duplicate_schemes_banner?(@organisation, current_user) %> + <%= govuk_notification_banner(title_text: "Important") do %> +

+ Some schemes and locations might be duplicates. +

+ <%= govuk_link_to "Review possible duplicates", href: schemes_duplicates_organisation_path(@organisation) %> + <% end %> +<% end %> +

<% if SchemePolicy.new(current_user, nil).create? %> <%= govuk_button_link_to "Create a new supported housing scheme", new_scheme_path, html: { method: :post } %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 50a821ce0..e3ef39517 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -37,6 +37,7 @@ en: updated: "Organisation details updated." reactivated: "%{organisation} has been reactivated." deactivated: "%{organisation} has been deactivated." + duplicate_schemes_confirmed: "You’ve confirmed the remaining schemes and locations are not duplicates." user: create_password: "Create a password to finish setting up your account." reset_password: "Reset your password." @@ -229,6 +230,7 @@ en: blank: "You must choose a managing agent." already_added: "You have already added this managing agent." merged: "That organisation has already been merged. Select a different organisation." + scheme_duplicates_not_resolved: "You must resolve all duplicates or indicate that there are no duplicates" not_answered: "You must answer %{question}" invalid_option: "Enter a valid value for %{question}" invalid_number: "Enter a number for %{question}" diff --git a/config/routes.rb b/config/routes.rb index 77b862e5a..ed6f47bbd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -178,6 +178,8 @@ Rails.application.routes.draw do get "schemes/csv-download", to: "organisations#download_schemes_csv" post "schemes/email-csv", to: "organisations#email_schemes_csv" get "schemes/csv-confirmation", to: "schemes#csv_confirmation" + get "schemes/duplicates", to: "organisations#duplicate_schemes" + post "schemes/duplicates", to: "organisations#confirm_duplicate_schemes" get "stock-owners", to: "organisation_relationships#stock_owners" get "stock-owners/add", to: "organisation_relationships#add_stock_owner" get "stock-owners/remove", to: "organisation_relationships#remove_stock_owner" diff --git a/db/migrate/20240920144611_add_schemes_deduplicated_at.rb b/db/migrate/20240920144611_add_schemes_deduplicated_at.rb new file mode 100644 index 000000000..02c1a6e05 --- /dev/null +++ b/db/migrate/20240920144611_add_schemes_deduplicated_at.rb @@ -0,0 +1,5 @@ +class AddSchemesDeduplicatedAt < ActiveRecord::Migration[7.0] + def change + add_column :organisations, :schemes_deduplicated_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index ff1f913df..174ae0199 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -514,6 +514,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_09_23_145326) do t.bigint "absorbing_organisation_id" t.datetime "available_from" t.datetime "discarded_at" + t.datetime "schemes_deduplicated_at" t.index ["absorbing_organisation_id"], name: "index_organisations_on_absorbing_organisation_id" t.index ["old_visible_id"], name: "index_organisations_on_old_visible_id", unique: true end diff --git a/lib/tasks/recalculate_status_when_la_missing.rake b/lib/tasks/recalculate_status_when_la_missing.rake index 16af29cc7..1e304c6fa 100644 --- a/lib/tasks/recalculate_status_when_la_missing.rake +++ b/lib/tasks/recalculate_status_when_la_missing.rake @@ -17,3 +17,22 @@ task recalculate_status_missing_la: :environment do end end end + +desc "Recalculates status for 2024 completed logs with missing LA" +task recalculate_status_missing_la_2024: :environment do + LettingsLog.filter_by_year(2024).where(needstype: 1, la: nil, status: "completed").find_each do |log| + log.status = log.calculate_status + + unless log.save + Rails.logger.info "Could not save changes to lettings log #{log.id}" + end + end + + SalesLog.filter_by_year(2024).where(la: nil, status: "completed").find_each do |log| + log.status = log.calculate_status + + unless log.save + Rails.logger.info "Could not save changes to sales log #{log.id}" + end + end +end diff --git a/public/files/2023_24_lettings_paper_form.pdf b/public/files/2023_24_lettings_paper_form.pdf deleted file mode 100644 index 9db94cc83..000000000 Binary files a/public/files/2023_24_lettings_paper_form.pdf and /dev/null differ diff --git a/public/files/2023_24_sales_paper_form.pdf b/public/files/2023_24_sales_paper_form.pdf deleted file mode 100644 index 1ad25cda0..000000000 Binary files a/public/files/2023_24_sales_paper_form.pdf and /dev/null differ diff --git a/public/files/2024_25_lettings_paper_form.pdf b/public/files/2024_25_lettings_paper_form.pdf deleted file mode 100644 index 910b28a19..000000000 Binary files a/public/files/2024_25_lettings_paper_form.pdf and /dev/null differ diff --git a/public/files/2024_25_sales_paper_form.pdf b/public/files/2024_25_sales_paper_form.pdf deleted file mode 100644 index 203757d9a..000000000 Binary files a/public/files/2024_25_sales_paper_form.pdf and /dev/null differ diff --git a/public/files/bulk-upload-lettings-legacy-template-2023-24.xlsx b/public/files/bulk-upload-lettings-legacy-template-2023-24.xlsx deleted file mode 100644 index 78050bd22..000000000 Binary files a/public/files/bulk-upload-lettings-legacy-template-2023-24.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-lettings-specification-2023-24.xlsx b/public/files/bulk-upload-lettings-specification-2023-24.xlsx deleted file mode 100644 index e7e56b6e3..000000000 Binary files a/public/files/bulk-upload-lettings-specification-2023-24.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-lettings-specification-2024-25.xlsx b/public/files/bulk-upload-lettings-specification-2024-25.xlsx deleted file mode 100644 index 577239804..000000000 Binary files a/public/files/bulk-upload-lettings-specification-2024-25.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-lettings-template-2023-24.xlsx b/public/files/bulk-upload-lettings-template-2023-24.xlsx deleted file mode 100644 index a0c46b73a..000000000 Binary files a/public/files/bulk-upload-lettings-template-2023-24.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-lettings-template-2024-25.xlsx b/public/files/bulk-upload-lettings-template-2024-25.xlsx deleted file mode 100644 index d0e0bfecd..000000000 Binary files a/public/files/bulk-upload-lettings-template-2024-25.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-sales-legacy-template-2023-24.xlsx b/public/files/bulk-upload-sales-legacy-template-2023-24.xlsx deleted file mode 100644 index d52e722e5..000000000 Binary files a/public/files/bulk-upload-sales-legacy-template-2023-24.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-sales-specification-2023-24.xlsx b/public/files/bulk-upload-sales-specification-2023-24.xlsx deleted file mode 100644 index 9d1d4be62..000000000 Binary files a/public/files/bulk-upload-sales-specification-2023-24.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-sales-specification-2024-25.xlsx b/public/files/bulk-upload-sales-specification-2024-25.xlsx deleted file mode 100644 index 5eab435c3..000000000 Binary files a/public/files/bulk-upload-sales-specification-2024-25.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-sales-template-2023-24.xlsx b/public/files/bulk-upload-sales-template-2023-24.xlsx deleted file mode 100644 index 773054750..000000000 Binary files a/public/files/bulk-upload-sales-template-2023-24.xlsx and /dev/null differ diff --git a/public/files/bulk-upload-sales-template-2024-25.xlsx b/public/files/bulk-upload-sales-template-2024-25.xlsx deleted file mode 100644 index f63878aa5..000000000 Binary files a/public/files/bulk-upload-sales-template-2024-25.xlsx and /dev/null differ diff --git a/spec/features/accessibility_spec.rb b/spec/features/accessibility_spec.rb index 97f632d92..2a95b684e 100644 --- a/spec/features/accessibility_spec.rb +++ b/spec/features/accessibility_spec.rb @@ -3,6 +3,7 @@ require "rails_helper" RSpec.describe "Accessibility", js: true do let(:user) { create(:user, :support) } let!(:other_user) { create(:user, name: "new user", organisation: user.organisation, email: "new_user@example.com", confirmation_token: "abc") } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } def find_routes(type, resource, subresource) routes = Rails.application.routes.routes.select do |route| @@ -20,6 +21,8 @@ RSpec.describe "Accessibility", js: true do end before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) allow(user).to receive(:need_two_factor_authentication?).and_return(false) sign_in(user) end diff --git a/spec/features/lettings_log_spec.rb b/spec/features/lettings_log_spec.rb index ac9a1e4a8..ea250529d 100644 --- a/spec/features/lettings_log_spec.rb +++ b/spec/features/lettings_log_spec.rb @@ -1,6 +1,13 @@ require "rails_helper" RSpec.describe "Lettings Log Features" do + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } + + before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) + end + context "when searching for specific logs" do context "when I am signed in and there are logs in the database" do let(:user) { create(:user, last_sign_in_at: Time.zone.now) } diff --git a/spec/features/notifications_spec.rb b/spec/features/notifications_spec.rb index e2bd4b151..a542cc97f 100644 --- a/spec/features/notifications_spec.rb +++ b/spec/features/notifications_spec.rb @@ -3,6 +3,12 @@ require_relative "form/helpers" RSpec.describe "Notifications Features" do include Helpers + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } + + before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) + end context "when there are notifications" do let!(:user) { FactoryBot.create(:user) } diff --git a/spec/features/organisation_spec.rb b/spec/features/organisation_spec.rb index 3d65cda87..98ae86475 100644 --- a/spec/features/organisation_spec.rb +++ b/spec/features/organisation_spec.rb @@ -10,8 +10,11 @@ RSpec.describe "User Features" do let(:notify_client) { instance_double(Notifications::Client) } let(:confirmation_token) { "MCDH5y6Km-U7CFPgAMVS" } let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) allow(Devise).to receive(:friendly_token).and_return(confirmation_token) diff --git a/spec/features/start_page_spec.rb b/spec/features/start_page_spec.rb index ab09fd446..555db9238 100644 --- a/spec/features/start_page_spec.rb +++ b/spec/features/start_page_spec.rb @@ -4,6 +4,12 @@ require_relative "form/helpers" RSpec.describe "Start Page Features" do include Helpers let(:user) { FactoryBot.create(:user) } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } + + before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) + end context "when the user is signed in" do before do diff --git a/spec/features/test_spec.rb b/spec/features/test_spec.rb index 6dc977a9b..a58867182 100644 --- a/spec/features/test_spec.rb +++ b/spec/features/test_spec.rb @@ -1,5 +1,12 @@ require "rails_helper" RSpec.describe "Test Features" do + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } + + before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) + end + it "Displays the name of the app" do visit(root_path) expect(page).to have_content("Submit social housing lettings and sales data (CORE)") diff --git a/spec/features/user_spec.rb b/spec/features/user_spec.rb index 119dbfa52..bc562824c 100644 --- a/spec/features/user_spec.rb +++ b/spec/features/user_spec.rb @@ -6,12 +6,15 @@ RSpec.describe "User Features" do let(:notify_client) { instance_double(Notifications::Client) } let(:reset_password_token) { "MCDH5y6Km-U7CFPgAMVS" } let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) allow(notify_client).to receive(:send_email).and_return(true) allow(Devise.token_generator).to receive(:generate).and_return(reset_password_token) + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) end context "when the user navigates to lettings logs" do diff --git a/spec/helpers/collection_resources_helper_spec.rb b/spec/helpers/collection_resources_helper_spec.rb index c028177ce..4d39a0c2d 100644 --- a/spec/helpers/collection_resources_helper_spec.rb +++ b/spec/helpers/collection_resources_helper_spec.rb @@ -3,15 +3,29 @@ require "rails_helper" RSpec.describe CollectionResourcesHelper do let(:current_user) { create(:user, :data_coordinator) } let(:user) { create(:user, :data_coordinator) } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } + + before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) + end describe "when displaying file metadata" do context "with pages" do + before do + allow(storage_service).to receive(:get_file_metadata).with("2023_24_lettings_paper_form.pdf").and_return("content_length" => 292_864, "content_type" => "application/pdf") + end + it "returns correct metadata" do expect(file_type_size_and_pages("2023_24_lettings_paper_form.pdf", number_of_pages: 8)).to eq("PDF, 286 KB, 8 pages") end end context "without pages" do + before do + allow(storage_service).to receive(:get_file_metadata).with("bulk-upload-lettings-template-2023-24.xlsx").and_return("content_length" => 19_456, "content_type" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + end + it "returns correct metadata" do expect(file_type_size_and_pages("bulk-upload-lettings-template-2023-24.xlsx")).to eq("Microsoft Excel, 19 KB") end diff --git a/spec/helpers/schemes_helper_spec.rb b/spec/helpers/schemes_helper_spec.rb index 0df032c3f..8ffde636a 100644 --- a/spec/helpers/schemes_helper_spec.rb +++ b/spec/helpers/schemes_helper_spec.rb @@ -118,4 +118,121 @@ RSpec.describe SchemesHelper do end end end + + describe "display_duplicate_schemes_banner?" do + let(:organisation) { create(:organisation) } + let(:current_user) { create(:user, :support) } + + context "when organisation has not absorbed other organisations" do + context "and it has duplicate schemes" do + before do + create_list(:scheme, 2, :duplicate, owning_organisation: organisation) + end + + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + end + + context "when organisation has absorbed other organisations in open collection year" do + before do + build(:organisation, merge_date: Time.zone.yesterday, absorbing_organisation_id: organisation.id).save(validate: false) + end + + context "and it has duplicate schemes" do + before do + create_list(:scheme, 2, :duplicate, owning_organisation: organisation) + end + + it "displays the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_truthy + end + + context "and organisation has confirmed duplicate schemes after the most recent merge" do + before do + organisation.update!(schemes_deduplicated_at: Time.zone.today) + end + + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + + context "and organisation has confirmed duplicate schemes before the most recent merge" do + before do + organisation.update!(schemes_deduplicated_at: Time.zone.today - 2.days) + end + + it "displays the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_truthy + end + end + end + + context "and it has duplicate locations" do + let(:scheme) { create(:scheme, owning_organisation: organisation) } + + before do + create_list(:location, 2, postcode: "AB1 2CD", mobility_type: "A", scheme:) + end + + it "displays the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_truthy + end + end + + context "and it has no duplicate schemes or locations" do + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + + context "and it is viewed by data provider" do + let(:current_user) { create(:user, :data_provider) } + + before do + create_list(:scheme, 2, :duplicate, owning_organisation: organisation) + end + + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + end + + context "when organisation has absorbed other organisations in closed collection year" do + before do + build(:organisation, merge_date: Time.zone.today - 2.years, absorbing_organisation_id: organisation.id).save(validate: false) + end + + context "and it has duplicate schemes" do + before do + create_list(:scheme, 2, :duplicate, owning_organisation: organisation) + end + + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + + context "and it has duplicate locations" do + let(:scheme) { create(:scheme, owning_organisation: organisation) } + + before do + create(:location, postcode: "AB1 2CD", mobility_type: "A", scheme:) + end + + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + + context "and it has no duplicate schemes or locations" do + it "does not display the banner" do + expect(display_duplicate_schemes_banner?(organisation, current_user)).to be_falsey + end + end + end + end end diff --git a/spec/requests/auth/passwords_controller_spec.rb b/spec/requests/auth/passwords_controller_spec.rb index 333985d9e..7f9bdfa30 100644 --- a/spec/requests/auth/passwords_controller_spec.rb +++ b/spec/requests/auth/passwords_controller_spec.rb @@ -5,11 +5,14 @@ RSpec.describe Auth::PasswordsController, type: :request do let(:page) { Capybara::Node::Simple.new(response.body) } let(:notify_client) { instance_double(Notifications::Client) } let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) allow(notify_client).to receive(:send_email).and_return(true) + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) end context "when a regular user" do diff --git a/spec/requests/maintenance_controller_spec.rb b/spec/requests/maintenance_controller_spec.rb index 39e587302..28287dbc0 100644 --- a/spec/requests/maintenance_controller_spec.rb +++ b/spec/requests/maintenance_controller_spec.rb @@ -3,8 +3,11 @@ require "rails_helper" RSpec.describe MaintenanceController, type: :request do let(:page) { Capybara::Node::Simple.new(response.body) } let(:user) { FactoryBot.create(:user) } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) sign_in user end diff --git a/spec/requests/organisations_controller_spec.rb b/spec/requests/organisations_controller_spec.rb index 91dc07094..223cc9e00 100644 --- a/spec/requests/organisations_controller_spec.rb +++ b/spec/requests/organisations_controller_spec.rb @@ -207,6 +207,24 @@ RSpec.describe OrganisationsController, type: :request do expect(page).to have_title("#{user.organisation.name} (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK") end end + + context "when organisation has absorbed other organisations" do + before do + create(:organisation, merge_date: Time.zone.today, absorbing_organisation: organisation) + end + + context "and it has duplicate schemes or locations" do + before do + create_list(:scheme, 2, :duplicate, owning_organisation: organisation) + get "/organisations/#{organisation.id}/schemes", headers:, params: {} + end + + it "displays a banner with correct content" do + expect(page).to have_content("Some schemes and locations might be duplicates.") + expect(page).to have_link("Review possible duplicates", href: "/organisations/#{organisation.id}/schemes/duplicates") + end + end + end end context "when data coordinator user" do @@ -348,6 +366,77 @@ RSpec.describe OrganisationsController, type: :request do end end + describe "#duplicate_schemes" do + context "with support user" do + let(:user) { create(:user, :support) } + + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/organisations/#{organisation.id}/schemes/duplicates", headers: + end + + context "with duplicate schemes and locations" do + let(:schemes) { create_list(:scheme, 5, :duplicate, owning_organisation: organisation) } + + before do + create_list(:location, 2, scheme: schemes.first, postcode: "M1 1AA", mobility_type: "M") + create_list(:location, 2, scheme: schemes.first, postcode: "M1 1AA", mobility_type: "A") + get "/organisations/#{organisation.id}/schemes/duplicates", headers: + end + + it "displays the duplicate schemes" do + expect(page).to have_content("This set of schemes might have duplicates") + end + + it "displays the duplicate locations" do + expect(page).to have_content("These 2 sets of locations might have duplicates") + end + + it "has page heading" do + expect(page).to have_content("Review these sets of schemes and locations") + end + end + + context "without duplicate schemes and locations" do + it "does not display the schemes" do + expect(page).not_to have_content("schemes might have duplicates") + end + + it "does not display the locations" do + expect(page).not_to have_content("locations might have duplicates") + end + end + end + + context "with data coordinator user" do + let(:user) { create(:user, :data_coordinator) } + + before do + sign_in user + create_list(:scheme, 5, :duplicate, owning_organisation: organisation) + get "/organisations/#{organisation.id}/schemes/duplicates", headers: + end + + it "has page heading" do + expect(page).to have_content("Review these sets of schemes") + end + end + + context "with data provider user" do + let(:user) { create(:user, :data_provider) } + + before do + sign_in user + get "/organisations/#{organisation.id}/schemes/duplicates", headers: + end + + it "be unauthorised" do + expect(response).to have_http_status(:unauthorized) + end + end + end + describe "#show" do context "with an organisation that the user belongs to" do let(:set_time) {} @@ -2263,4 +2352,65 @@ RSpec.describe OrganisationsController, type: :request do end end end + + describe "POST #confirm_duplicate_schemes" do + let(:organisation) { create(:organisation) } + + context "when not signed in" do + it "redirects to sign in" do + post "/organisations/#{organisation.id}/schemes/duplicates", headers: headers + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in" do + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + end + + context "when user is data provider" do + let(:user) { create(:user, role: "data_provider", organisation:) } + + it "returns not found" do + post "/organisations/#{organisation.id}/schemes/duplicates", headers: headers + expect(response).to have_http_status(:unauthorized) + end + end + + context "when user is coordinator" do + let(:user) { create(:user, role: "data_coordinator", organisation:) } + + context "and the duplicate schemes have been confirmed" do + let(:params) { { "organisation": { scheme_duplicates_checked: "true" } } } + + it "redirects to schemes page" do + post "/organisations/#{organisation.id}/schemes/duplicates", headers: headers, params: params + + expect(response).to redirect_to("/organisations/#{organisation.id}/schemes") + expect(flash[:notice]).to eq("You’ve confirmed the remaining schemes and locations are not duplicates.") + end + + it "updates schemes_deduplicated_at" do + expect(organisation.reload.schemes_deduplicated_at).to be_nil + + post "/organisations/#{organisation.id}/schemes/duplicates", headers: headers, params: params + + expect(organisation.reload.schemes_deduplicated_at).not_to be_nil + end + end + + context "and the duplicate schemes have not been confirmed" do + let(:params) { { "organisation": { scheme_duplicates_checked: "" } } } + + it "displays an error" do + post "/organisations/#{organisation.id}/schemes/duplicates", headers: headers, params: params + + expect(response).to have_http_status(:unprocessable_entity) + expect(page).to have_content("You must resolve all duplicates or indicate that there are no duplicates") + end + end + end + end + end end diff --git a/spec/requests/rails_admin_controller_spec.rb b/spec/requests/rails_admin_controller_spec.rb index 4d0bbb7c2..79f56d18f 100644 --- a/spec/requests/rails_admin_controller_spec.rb +++ b/spec/requests/rails_admin_controller_spec.rb @@ -4,9 +4,12 @@ RSpec.describe "RailsAdmin", type: :request do let(:user) { create(:user) } let(:support_user) { create(:user, :support) } let(:page) { Capybara::Node::Simple.new(response.body) } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do allow(support_user).to receive(:need_two_factor_authentication?).and_return(false) + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) end describe "GET /admin" do diff --git a/spec/requests/start_controller_spec.rb b/spec/requests/start_controller_spec.rb index 699bdfa9c..40c45a9f9 100644 --- a/spec/requests/start_controller_spec.rb +++ b/spec/requests/start_controller_spec.rb @@ -5,11 +5,14 @@ RSpec.describe StartController, type: :request do let(:page) { Capybara::Node::Simple.new(response.body) } let(:notify_client) { instance_double(Notifications::Client) } let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) allow(notify_client).to receive(:send_email).and_return(true) + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) end describe "GET" do diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 1ab5aa9d4..05dc06d5b 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -10,11 +10,14 @@ RSpec.describe UsersController, type: :request do let(:params) { { id: user.id, user: { name: new_name } } } let(:notify_client) { instance_double(Notifications::Client) } let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } before do allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) allow(notify_client).to receive(:send_email).and_return(true) + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) end context "when user is not signed in" do