Browse Source

CLDC-3640 Upload new mandatory collection resources (#2683)

* Stub some collection resource requests

* Update upload new mandatory resource page

* Add next year resources banner

* Display next collection resources to users when released

* Add confirm_mandatory_collection_resources_release page

* Allow releasing resources to users

* Rebase changes
pull/2687/head^2
kosiakkatrina 3 months ago committed by GitHub
parent
commit
75563afbd1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 23
      app/controllers/collection_resources_controller.rb
  2. 17
      app/helpers/collection_resources_helper.rb
  3. 5
      app/models/collection_resource.rb
  4. 11
      app/services/mandatory_collection_resources_service.rb
  5. 6
      app/services/storage/local_disk_service.rb
  6. 2
      app/views/collection_resources/_collection_resource_summary_list.erb
  7. 27
      app/views/collection_resources/confirm_mandatory_collection_resources_release.erb
  8. 5
      app/views/collection_resources/edit.html.erb
  9. 8
      app/views/collection_resources/index.html.erb
  10. 9
      config/locales/en.yml
  11. 2
      config/routes.rb
  12. 15
      db/migrate/20241008100119_add_collection_resources_table.rb
  13. 15
      db/schema.rb
  14. 72
      spec/helpers/collection_resources_helper_spec.rb
  15. 192
      spec/requests/collection_resources_controller_spec.rb

23
app/controllers/collection_resources_controller.rb

@ -68,6 +68,29 @@ class CollectionResourcesController < ApplicationController
redirect_to collection_resources_path
end
def confirm_mandatory_collection_resources_release
return render_not_found unless current_user.support?
@year = params[:year].to_i
return render_not_found unless editable_collection_resource_years.include?(@year)
render "collection_resources/confirm_mandatory_collection_resources_release"
end
def release_mandatory_collection_resources
return render_not_found unless current_user.support?
year = params[:year].to_i
return render_not_found unless editable_collection_resource_years.include?(year)
MandatoryCollectionResourcesService.release_resources(year)
flash[:notice] = "The #{text_year_range_format(year)} collection resources are now available to users."
redirect_to collection_resources_path
end
private
def resource_params

17
app/helpers/collection_resources_helper.rb

@ -1,5 +1,7 @@
module CollectionResourcesHelper
include CollectionTimeHelper
include GovukLinkHelper
include GovukVisuallyHiddenHelper
HUMAN_READABLE_CONTENT_TYPE = { "application/pdf": "PDF",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "Microsoft Excel",
@ -24,6 +26,7 @@ module CollectionResourcesHelper
def displayed_collection_resource_years
return [previous_collection_start_year, current_collection_start_year] if FormHandler.instance.in_edit_crossover_period?
return [current_collection_start_year, next_collection_start_year] if CollectionResource.where(year: next_collection_start_year, mandatory: true, released_to_user: true).any?
[current_collection_start_year]
end
@ -66,4 +69,18 @@ module CollectionResourcesHelper
def file_exists_on_s3?(file)
CollectionResourcesService.new.file_exists_on_s3?(file)
end
def display_next_year_banner?
return false if CollectionResource.where(year: next_collection_start_year, mandatory: true, released_to_user: true).any?
editable_collection_resource_years.include?(next_collection_start_year)
end
def next_year_banner_text(lettings_resources, sales_resources)
if lettings_resources[next_collection_start_year].map(&:download_filename).all? { |file| file_exists_on_s3?(file) } && sales_resources[next_collection_start_year].map(&:download_filename).all? { |file| file_exists_on_s3?(file) }
govuk_link_to "Release the #{text_year_range_format(next_collection_start_year)} collection resources to users", release_mandatory_collection_resources_path(year: next_collection_start_year), class: "govuk-link"
else
"Once you have uploaded all the required #{text_year_range_format(next_collection_start_year)} collection resources, you will be able to release them to users."
end
end
end

5
app/models/collection_resource.rb

@ -1,8 +1,7 @@
class CollectionResource
include ActiveModel::Model
class CollectionResource < ApplicationRecord
include Rails.application.routes.url_helpers
attr_accessor :resource_type, :display_name, :short_display_name, :year, :log_type, :download_filename, :file
attr_accessor :file
def download_path
download_mandatory_collection_resource_path(log_type:, year:, resource_type:)

11
app/services/mandatory_collection_resources_service.rb

@ -30,6 +30,17 @@ class MandatoryCollectionResourcesService
)
end
def self.release_resources(year)
sales_resources = resources_per_year(year, "sales")
lettings_resources = resources_per_year(year, "lettings")
(sales_resources + lettings_resources).each do |resource|
resource.released_to_user = true
resource.mandatory = true
resource.save!
end
end
def self.display_name(resource, year, log_type)
year_range = "#{year} to #{year + 1}"
case resource

6
app/services/storage/local_disk_service.rb

@ -37,5 +37,11 @@ module Storage
"content_type" => MiniMime.lookup_by_filename(path.to_s)&.content_type || "application/octet-stream",
}
end
def file_exists?(filename)
path = Rails.root.join("tmp/storage", filename)
File.exist?(path)
end
end
end

2
app/views/collection_resources/_collection_resource_summary_list.erb

@ -18,7 +18,7 @@
<% end %>
<% row.with_action(
text: "Upload",
href: "/",
href: edit_mandatory_collection_resource_path(year: resource.year, log_type: resource.log_type, resource_type: resource.resource_type),
) %>
<% end %>
<% end %>

27
app/views/collection_resources/confirm_mandatory_collection_resources_release.erb

@ -0,0 +1,27 @@
<% content_for :before_content do %>
<% content_for :title, "Are you sure you want to release the #{text_year_range_format(@year)} collection resources?" %>
<%= govuk_back_link(href: collection_resources_path) %>
<% 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">
The files uploaded will immediately become available for users to download.
</p>
<%= govuk_warning_text(text: "You will not be able to undo this action.") %>
<div class="govuk-button-group">
<%= govuk_button_to(
"Release the resources",
release_mandatory_collection_resources_path(year: @year),
method: :patch,
) %>
<%= govuk_button_link_to "Cancel", collection_resources_path, secondary: true %>
</div>
</div>
</div>

5
app/views/collection_resources/edit.html.erb

@ -4,6 +4,7 @@
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<% resource_exists = file_exists_on_s3?(@collection_resource.download_filename) %>
<%= form_with model: @collection_resource, url: update_mandatory_collection_resource_path, method: :patch do |f| %>
<%= f.hidden_field :year %>
<%= f.hidden_field :log_type %>
@ -12,7 +13,7 @@
<%= f.govuk_error_summary %>
<span class="govuk-caption-l"><%= "#{@collection_resource.log_type.humanize} #{text_year_range_format(@collection_resource.year)}" %></span>
<h1 class="govuk-heading-l">Change the <%= @collection_resource.resource_type.humanize.downcase %></h1>
<h1 class="govuk-heading-l"><%= resource_exists ? "Change" : "Upload" %> the <%= @collection_resource.resource_type.humanize.downcase %></h1>
<p class="govuk-body">
This file will be available for all users to download.
@ -21,7 +22,7 @@
<%= f.govuk_file_field :file,
label: { text: "Upload file", size: "m" } %>
<%= f.govuk_submit "Save changes" %>
<%= f.govuk_submit resource_exists ? "Save changes" : "Upload" %>
<%= govuk_button_link_to "Cancel", collection_resources_path, secondary: true %>
<% end %>
</div>

8
app/views/collection_resources/index.html.erb

@ -4,6 +4,14 @@
<%= govuk_back_link(href: :back) %>
<% end %>
<% if display_next_year_banner? %>
<%= govuk_notification_banner(title_text: "Important") do %>
<p class="govuk-notification-banner__heading govuk-!-width-full" style="max-width: fit-content">
The <%= text_year_range_format(next_collection_start_year) %> collection resources are not yet available to users.
<p>
<%= next_year_banner_text(@mandatory_lettings_collection_resources_per_year, @mandatory_sales_collection_resources_per_year) %>
<% end %>
<% end %>
<h1 class="govuk-heading-l"><%= title %></h1>
<% @mandatory_lettings_collection_resources_per_year.each do |year, mandatory_resources| %>

9
config/locales/en.yml

@ -207,7 +207,14 @@ en:
blank_when_additional_page_set: "Enter the link text."
page_content:
blank_when_additional_page_set: "Enter the page content."
collection_resource:
attributes:
file:
error_uploading: There was an error uploading this file.
blank: Select which file to upload.
above_100_mb: The file is above 100MB.
must_be_pdf: The paper form must be a PDF.
must_be_xlsx: The %{resource} must be a Microsoft Excel file.
notification:
logs_deleted:
one: "%{count} log has been deleted."

2
config/routes.rb

@ -44,6 +44,8 @@ Rails.application.routes.draw do
get "/collection-resources/:log_type/:year/:resource_type/download", to: "collection_resources#download_mandatory_collection_resource", as: :download_mandatory_collection_resource
get "/collection-resources/:log_type/:year/:resource_type/edit", to: "collection_resources#edit", as: :edit_mandatory_collection_resource
patch "/collection-resources", to: "collection_resources#update", as: :update_mandatory_collection_resource
get "/collection-resources/:year/release", to: "collection_resources#confirm_mandatory_collection_resources_release", as: :confirm_mandatory_collection_resources_release
patch "/collection-resources/:year/release", to: "collection_resources#release_mandatory_collection_resources", as: :release_mandatory_collection_resources
resources :collection_resources, path: "/collection-resources" do
get "/download", to: "collection_resources#download_additional_collection_resource" # when we get to adding them

15
db/migrate/20241008100119_add_collection_resources_table.rb

@ -0,0 +1,15 @@
class AddCollectionResourcesTable < ActiveRecord::Migration[7.0]
def change
create_table :collection_resources do |t|
t.column :log_type, :string
t.column :resource_type, :string
t.column :display_name, :string
t.column :short_display_name, :string
t.column :year, :integer
t.column :download_filename, :string
t.column :mandatory, :boolean
t.column :released_to_user, :boolean
t.timestamps
end
end
end

15
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_10_02_163937) do
ActiveRecord::Schema[7.0].define(version: 2024_10_08_100119) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -50,6 +50,19 @@ ActiveRecord::Schema[7.0].define(version: 2024_10_02_163937) do
t.index ["user_id"], name: "index_bulk_uploads_on_user_id"
end
create_table "collection_resources", force: :cascade do |t|
t.string "log_type"
t.string "resource_type"
t.string "display_name"
t.string "short_display_name"
t.integer "year"
t.string "download_filename"
t.boolean "mandatory"
t.boolean "released_to_user"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "csv_variable_definitions", force: :cascade do |t|
t.string "variable", null: false
t.string "definition", null: false

72
spec/helpers/collection_resources_helper_spec.rb

@ -91,6 +91,18 @@ RSpec.describe CollectionResourcesHelper do
it "returns current year" do
expect(displayed_collection_resource_years).to eq([2024])
end
context "and next year resources were manually released" do
before do
CollectionResource.create!(year: 2025, resource_type: "paper_form", display_name: "lettings log for tenants (2025 to 2026)", download_filename: "file.pdf", mandatory: true, released_to_user: true)
CollectionResource.create!(year: 2025, resource_type: "bulk_upload_template", display_name: "bulk upload template (2025 to 2026)", download_filename: "file.xlsx", mandatory: true, released_to_user: true)
CollectionResource.create!(year: 2025, resource_type: "bulk_upload_specification", display_name: "sales log for tenants (2025 to 2026)", download_filename: "file.xlsx", mandatory: true, released_to_user: true)
end
it "reutrns current and next years" do
expect(displayed_collection_resource_years).to eq([2024, 2025])
end
end
end
end
@ -163,4 +175,64 @@ RSpec.describe CollectionResourcesHelper do
])
end
end
describe "#display_next_year_banner?" do
context "when next year is not editable" do
before do
allow(FormHandler.instance).to receive(:in_edit_crossover_period?).and_return(true)
end
it "returns false" do
expect(display_next_year_banner?).to be_falsey
end
end
context "when next year is editable" do
before do
allow(FormHandler.instance).to receive(:in_edit_crossover_period?).and_return(false)
allow(Time.zone).to receive(:today).and_return(Time.zone.local(2025, 1, 1))
end
it "returns true" do
expect(display_next_year_banner?).to be_truthy
end
context "and the resources have been manually released" do
before do
CollectionResource.create!(year: 2025, resource_type: "paper_form", display_name: "lettings log for tenants (2025 to 2026)", download_filename: "file.pdf", mandatory: true, released_to_user: true)
CollectionResource.create!(year: 2025, resource_type: "bulk_upload_template", display_name: "bulk upload template (2025 to 2026)", download_filename: "file.xlsx", mandatory: true, released_to_user: true)
CollectionResource.create!(year: 2025, resource_type: "bulk_upload_specification", display_name: "sales log for tenants (2025 to 2026)", download_filename: "file.xlsx", mandatory: true, released_to_user: true)
end
it "returns false" do
expect(display_next_year_banner?).to be_falsey
end
end
end
end
describe "#next_year_banner_text" do
let(:lettings_resources) { MandatoryCollectionResourcesService.generate_resources("lettings", [next_collection_start_year]) }
let(:sales_resources) { MandatoryCollectionResourcesService.generate_resources("sales", [next_collection_start_year]) }
context "when all the mandatory resources for next year are uploaded" do
before do
allow(storage_service).to receive(:file_exists?).and_return(true)
end
it "returns correct text" do
expect(next_year_banner_text(lettings_resources, sales_resources)).to match(/Release the 2025 to 2026 collection resources to users/)
end
end
context "when some of the mandatory resources for next year are not uploaded" do
before do
allow(storage_service).to receive(:file_exists?).and_return(false)
end
it "returns correct text" do
expect(next_year_banner_text(lettings_resources, sales_resources)).to eq("Once you have uploaded all the required 2025 to 2026 collection resources, you will be able to release them to users.")
end
end
end
end

192
spec/requests/collection_resources_controller_spec.rb

@ -108,6 +108,11 @@ RSpec.describe CollectionResourcesController, type: :request do
expect(page).to have_link("Change", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "sales", resource_type: "bulk_upload_template"))
expect(page).to have_link("Change", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "sales", resource_type: "bulk_upload_specification"))
end
it "displays next year banner" do
expect(page).to have_content("The 2025 to 2026 collection resources are not yet available to users.")
expect(page).to have_link("Release the 2025 to 2026 collection resources to users", href: confirm_mandatory_collection_resources_release_path(year: 2025))
end
end
context "when files are not on S3" do
@ -122,6 +127,24 @@ RSpec.describe CollectionResourcesController, type: :request do
it "displays upload links" do
expect(page).to have_selector(:link_or_button, "Upload", count: 12)
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2024, log_type: "lettings", resource_type: "paper_form"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2024, log_type: "lettings", resource_type: "bulk_upload_template"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2024, log_type: "lettings", resource_type: "bulk_upload_specification"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2024, log_type: "sales", resource_type: "paper_form"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2024, log_type: "sales", resource_type: "bulk_upload_template"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2024, log_type: "sales", resource_type: "bulk_upload_specification"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "lettings", resource_type: "paper_form"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "lettings", resource_type: "bulk_upload_template"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "lettings", resource_type: "bulk_upload_specification"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "sales", resource_type: "paper_form"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "sales", resource_type: "bulk_upload_template"))
expect(page).to have_link("Upload", href: edit_mandatory_collection_resource_path(year: 2025, log_type: "sales", resource_type: "bulk_upload_specification"))
end
it "displays next year banner" do
expect(page).to have_content("The 2025 to 2026 collection resources are not yet available to users.")
expect(page).to have_content("Once you have uploaded all the required 2025 to 2026 collection resources, you will be able to release them to users.")
end
end
end
@ -243,16 +266,40 @@ RSpec.describe CollectionResourcesController, type: :request do
sign_in user
end
it "displays update collection resources page content" do
get edit_mandatory_collection_resource_path(year: 2024, log_type: "sales", resource_type: "bulk_upload_template")
context "and the file exists on S3" do
before do
allow(storage_service).to receive(:file_exists?).and_return(true)
end
expect(page).to have_content("Sales 2024 to 2025")
expect(page).to have_content("Change the bulk upload template")
expect(page).to have_content("This file will be available for all users to download.")
expect(page).to have_content("Upload file")
expect(page).to have_button("Save changes")
expect(page).to have_link("Back", href: collection_resources_path)
expect(page).to have_link("Cancel", href: collection_resources_path)
it "displays update collection resources page content" do
get edit_mandatory_collection_resource_path(year: 2024, log_type: "sales", resource_type: "bulk_upload_template")
expect(page).to have_content("Sales 2024 to 2025")
expect(page).to have_content("Change the bulk upload template")
expect(page).to have_content("This file will be available for all users to download.")
expect(page).to have_content("Upload file")
expect(page).to have_button("Save changes")
expect(page).to have_link("Back", href: collection_resources_path)
expect(page).to have_link("Cancel", href: collection_resources_path)
end
end
context "and the file does not exist on S3" do
before do
allow(storage_service).to receive(:file_exists?).and_return(false)
end
it "displays upload collection resources page content" do
get edit_mandatory_collection_resource_path(year: 2024, log_type: "sales", resource_type: "bulk_upload_template")
expect(page).to have_content("Sales 2024 to 2025")
expect(page).to have_content("Upload the bulk upload template")
expect(page).to have_content("This file will be available for all users to download.")
expect(page).to have_content("Upload file")
expect(page).to have_button("Upload")
expect(page).to have_link("Back", href: collection_resources_path)
expect(page).to have_link("Cancel", href: collection_resources_path)
end
end
end
end
@ -299,4 +346,131 @@ RSpec.describe CollectionResourcesController, type: :request do
end
end
end
describe "GET #confirm_mandatory_collection_resources_release" do
context "when user is not signed in" do
it "redirects to the sign in page" do
get confirm_mandatory_collection_resources_release_path(year: 2025)
expect(response).to redirect_to(new_user_session_path)
end
end
context "when user is signed in as a data coordinator" do
let(:user) { create(:user, :data_coordinator) }
before do
sign_in user
end
it "returns page not found" do
get confirm_mandatory_collection_resources_release_path(year: 2025)
expect(response).to have_http_status(:not_found)
end
end
context "when user is signed in as a data provider" do
let(:user) { create(:user, :data_provider) }
before do
sign_in user
end
it "returns page not found" do
get confirm_mandatory_collection_resources_release_path(year: 2025)
expect(response).to have_http_status(:not_found)
end
end
context "when user is signed in as a support user" do
let(:user) { create(:user, :support) }
before do
# rubocop:disable RSpec/AnyInstance
allow_any_instance_of(CollectionResourcesHelper).to receive(:editable_collection_resource_years).and_return([2025])
# rubocop:enable RSpec/AnyInstance
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
end
it "displays correct page content" do
get confirm_mandatory_collection_resources_release_path(year: 2025)
expect(page).to have_content("Are you sure you want to release the 2025 to 2026 collection resources?")
expect(page).to have_content("The files uploaded will immediately become available for users to download.")
expect(page).to have_content("You will not be able to undo this action.")
expect(page).to have_button("Release the resources")
expect(page).to have_link("Cancel", href: collection_resources_path)
expect(page).to have_link("Back", href: collection_resources_path)
end
end
end
describe "PATCH #release_mandatory_collection_resources_path" do
let(:some_file) { File.open(file_fixture("blank_bulk_upload_sales.csv")) }
let(:collection_resource_service) { instance_double(CollectionResourcesService) }
before do
allow(CollectionResourcesService).to receive(:new).and_return(collection_resource_service)
end
context "when user is not signed in" do
it "redirects to the sign in page" do
patch release_mandatory_collection_resources_path(year: 2024)
expect(response).to redirect_to(new_user_session_path)
end
end
context "when user is signed in as a data coordinator" do
let(:user) { create(:user, :data_coordinator) }
before do
sign_in user
end
it "returns page not found" do
patch release_mandatory_collection_resources_path(year: 2024)
expect(response).to have_http_status(:not_found)
end
end
context "when user is signed in as a data provider" do
let(:user) { create(:user, :data_provider) }
before do
sign_in user
end
it "returns page not found" do
patch release_mandatory_collection_resources_path(year: 2024)
expect(response).to have_http_status(:not_found)
end
end
context "when user is signed in as a support user" do
let(:user) { create(:user, :support) }
before do
# rubocop:disable RSpec/AnyInstance
allow_any_instance_of(CollectionResourcesHelper).to receive(:editable_collection_resource_years).and_return([2025])
# rubocop:enable RSpec/AnyInstance
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
end
it "saves resources as released to users" do
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true).count).to eq(0)
patch release_mandatory_collection_resources_path(year: 2025)
expect(CollectionResource.all.count).to eq(6)
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true, log_type: "sales", resource_type: "paper_form").count).to eq(1)
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true, log_type: "sales", resource_type: "bulk_upload_template").count).to eq(1)
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true, log_type: "sales", resource_type: "bulk_upload_specification").count).to eq(1)
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true, log_type: "lettings", resource_type: "paper_form").count).to eq(1)
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true, log_type: "lettings", resource_type: "bulk_upload_template").count).to eq(1)
expect(CollectionResource.where(year: 2025, mandatory: true, released_to_user: true, log_type: "lettings", resource_type: "bulk_upload_specification").count).to eq(1)
expect(response).to redirect_to(collection_resources_path)
expect(flash[:notice]).to eq("The 2025 to 2026 collection resources are now available to users.")
end
end
end
end

Loading…
Cancel
Save