Browse Source

Merge branch 'main' into CLDC-1436-csv-schemes-info

# Conflicts:
#	app/services/csv/case_log_csv_service.rb
#	spec/fixtures/files/case_logs_download.csv
#	spec/services/csv/case_log_csv_service_spec.rb
pull/852/head
natdeanlewissoftwire 3 years ago
parent
commit
6f374c90d0
  1. 53
      app/models/case_log.rb
  2. 23
      app/models/derived_variables/case_log_variables.rb
  3. 2
      app/models/scheme.rb
  4. 10
      app/models/validations/household_validations.rb
  5. 24
      app/services/archive_storage_service.rb
  6. 54
      app/services/configuration/configuration_service.rb
  7. 37
      app/services/configuration/env_configuration_service.rb
  8. 23
      app/services/configuration/paas_configuration_service.rb
  9. 9
      app/services/imports/case_logs_import_service.rb
  10. 62
      app/services/paas_configuration_service.rb
  11. 78
      app/services/s3_storage_service.rb
  12. 26
      app/services/storage/archive_service.rb
  13. 80
      app/services/storage/s3_service.rb
  14. 19
      app/services/storage/storage_service.rb
  15. 17
      app/services/storage_service.rb
  16. 76
      config/forms/2021_2022.json
  17. 76
      config/forms/2022_2023.json
  18. 5
      config/initializers/rack_attack.rb
  19. 4
      config/locales/en.yml
  20. 8
      db/migrate/20220809100723_add_accessibility_requirements_fields.rb
  21. 43
      docs/infrastructure.md
  22. 2
      lib/tasks/data_export.rake
  23. 2
      lib/tasks/data_import.rake
  24. 2
      lib/tasks/data_import_field.rake
  25. 4
      lib/tasks/full_import.rake
  26. 3
      spec/factories/case_log.rb
  27. 16
      spec/features/form/checkboxes_spec.rb
  28. 9
      spec/fixtures/complete_case_log.json
  29. 48
      spec/fixtures/forms/2021_2022.json
  30. 12
      spec/lib/tasks/data_export_spec.rb
  31. 22
      spec/lib/tasks/data_import_spec.rb
  32. 14
      spec/lib/tasks/date_import_field_spec.rb
  33. 12
      spec/lib/tasks/full_import_spec.rb
  34. 125
      spec/models/case_log_spec.rb
  35. 40
      spec/models/validations/household_validations_spec.rb
  36. 128
      spec/services/configuration/env_configuration_service_spec.rb
  37. 120
      spec/services/configuration/paas_configuration_service_spec.rb
  38. 18
      spec/services/csv/case_log_csv_service_spec.rb
  39. 2
      spec/services/exports/case_log_export_service_spec.rb
  40. 2
      spec/services/imports/case_logs_field_import_service_spec.rb
  41. 2
      spec/services/imports/case_logs_import_service_spec.rb
  42. 2
      spec/services/imports/data_protection_confirmation_import_service_spec.rb
  43. 2
      spec/services/imports/organisation_import_service_spec.rb
  44. 2
      spec/services/imports/organisation_rent_period_import_service_spec.rb
  45. 2
      spec/services/imports/scheme_import_service_spec.rb
  46. 2
      spec/services/imports/scheme_location_import_service_spec.rb
  47. 2
      spec/services/imports/user_import_service_spec.rb
  48. 2
      spec/services/storage/archive_service_spec.rb
  49. 28
      spec/services/storage/s3_service_spec.rb

53
app/models/case_log.rb

@ -567,7 +567,6 @@ private
def reset_derived_questions
dependent_questions = { waityear: [{ key: :renewal, value: 0 }],
homeless: [{ key: :renewal, value: 0 }],
referral: [{ key: :renewal, value: 0 }],
underoccupation_benefitcap: [{ key: :renewal, value: 0 }],
wchair: [{ key: :needstype, value: 1 }],
@ -693,30 +692,6 @@ private
end
end
def get_housingneeds
return 1 if has_housingneeds?
return 2 if no_housingneeds?
return 3 if unknown_housingneeds?
end
def has_housingneeds?
if [housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f].any?(1)
1
end
end
def no_housingneeds?
if housingneeds_g == 1
1
end
end
def unknown_housingneeds?
if housingneeds_h == 1
1
end
end
def all_fields_completed?
subsection_statuses = form.subsections.map { |subsection| subsection.status(self) }.uniq
subsection_statuses == [:completed]
@ -754,4 +729,32 @@ private
def upcase_and_remove_whitespace(string)
string.present? ? string.upcase.gsub(/\s+/, "") : string
end
def fully_wheelchair_accessible?
housingneeds_type.present? && housingneeds_type.zero?
end
def essential_wheelchair_access?
housingneeds_type == 1
end
def level_access_housing?
housingneeds_type == 2
end
def other_housingneeds?
housingneeds_other == 1
end
def has_housingneeds?
housingneeds == 1
end
def no_housingneeds?
housingneeds == 2
end
def unknown_housingneeds?
housingneeds == 3
end
end

23
app/models/derived_variables/case_log_variables.rb

@ -43,10 +43,8 @@ module DerivedVariables::CaseLogVariables
self.has_benefits = get_has_benefits
self.tshortfall_known = 0 if tshortfall
self.nocharge = household_charge&.zero? ? 1 : 0
self.housingneeds = get_housingneeds
if is_renewal?
self.underoccupation_benefitcap = 2 if collection_start_year == 2021
self.homeless = 1
self.referral = 0
self.waityear = 2
if is_general_needs?
@ -70,6 +68,8 @@ module DerivedVariables::CaseLogVariables
self.voiddate = startdate
end
end
set_housingneeds_fields if housingneeds?
end
private
@ -186,4 +186,23 @@ private
self.location = scheme.locations.first
end
end
def set_housingneeds_fields
self.housingneeds_a = fully_wheelchair_accessible? ? 1 : 0
self.housingneeds_b = essential_wheelchair_access? ? 1 : 0
self.housingneeds_c = level_access_housing? ? 1 : 0
self.housingneeds_f = other_housingneeds? ? 1 : 0
set_housingneeds_values_to_zero unless has_housingneeds?
self.housingneeds_g = no_housingneeds? ? 1 : 0
self.housingneeds_h = unknown_housingneeds? ? 1 : 0
end
def set_housingneeds_values_to_zero
self.housingneeds_a = 0
self.housingneeds_b = 0
self.housingneeds_c = 0
self.housingneeds_f = 0
self.housingneeds_g = 0
self.housingneeds_h = 0
end
end

2
app/models/scheme.rb

@ -112,7 +112,7 @@ class Scheme < ApplicationRecord
def check_details_attributes
[
{ name: "Service code", value: id_to_display, id: "id" },
{ name: "Scheme code", value: id_to_display, id: "id" },
{ name: "Name", value: service_name, id: "service_name" },
{ name: "Confidential information", value: sensitive, id: "sensitive" },
{ name: "Type of scheme", value: scheme_type, id: "scheme_type" },

10
app/models/validations/household_validations.rb

@ -54,16 +54,6 @@ module Validations::HouseholdValidations
validate_person_age_matches_economic_status(record, 1)
end
def validate_accessibility_requirements(record)
all_options = [record.housingneeds_a, record.housingneeds_b, record.housingneeds_c, record.housingneeds_f, record.housingneeds_g, record.housingneeds_h]
if all_options.count(1) > 1
mobility_accessibility_options = [record.housingneeds_a, record.housingneeds_b, record.housingneeds_c]
unless all_options.count(1) == 2 && record.housingneeds_f == 1 && mobility_accessibility_options.any? { |x| x == 1 }
record.errors.add :accessibility_requirements, I18n.t("validations.household.housingneeds_a.one_or_two_choices")
end
end
end
def validate_condition_effects(record)
all_options = [record.illness_type_1, record.illness_type_2, record.illness_type_3, record.illness_type_4, record.illness_type_5, record.illness_type_6, record.illness_type_7, record.illness_type_8, record.illness_type_9, record.illness_type_10]
if all_options.count(1) >= 1 && household_no_illness?(record)

24
app/services/archive_storage_service.rb

@ -1,24 +0,0 @@
class ArchiveStorageService < StorageService
MAX_SIZE = 50 * (1024**2) # 50MiB
def initialize(archive_io)
super()
@archive = Zip::File.open_buffer(archive_io)
end
def list_files(folder)
@archive.glob(File.join(folder, "*.*"))
.map(&:name)
end
def folder_present?(folder)
!list_files(folder).empty?
end
def get_file_io(file_name)
entry = @archive.get_entry(file_name)
raise "File too large to be extracted" if entry.size > MAX_SIZE
entry.get_input_stream
end
end

54
app/services/configuration/configuration_service.rb

@ -0,0 +1,54 @@
module Configuration
class ConfigurationService
attr_reader :s3_buckets, :redis_uris
def initialize(logger = Rails.logger)
@logger = logger
@config = read_config
@s3_buckets = read_s3_buckets
@redis_uris = read_redis_uris
end
def s3_config_present?
config_present? && @config.key?(:"aws-s3-bucket")
end
def redis_config_present?
config_present? && @config.key?(:redis)
end
private
def config_present?
raise NotImplementedError
end
def read_config
raise NotImplementedError
end
def read_s3_buckets
return {} unless s3_config_present?
s3_buckets = {}
@config[:"aws-s3-bucket"].each do |bucket_config|
if bucket_config.key?(:instance_name)
s3_buckets[bucket_config[:instance_name].to_sym] = bucket_config
end
end
s3_buckets
end
def read_redis_uris
return {} unless redis_config_present?
redis_uris = {}
@config[:redis].each do |redis_config|
if redis_config.key?(:instance_name)
redis_uris[redis_config[:instance_name].to_sym] = redis_config.dig(:credentials, :uri)
end
end
redis_uris
end
end
end

37
app/services/configuration/env_configuration_service.rb

@ -0,0 +1,37 @@
module Configuration
class EnvConfigurationService < ConfigurationService
private
def config_present?
!ENV["S3_CONFIG"].nil? || !ENV["REDIS_CONFIG"].nil?
end
def read_config
unless config_present?
@logger.warn("Could not find S3_CONFIG or REDIS_CONFIG in the environment variables!")
return {}
end
config = {}
assign_config(config, :"aws-s3-bucket", "S3_CONFIG")
assign_config(config, :redis, "REDIS_CONFIG")
config
end
def assign_config(config, symbol, env_variable)
config_hash = parse_json_config(env_variable)
config[symbol] = config_hash unless config_hash.empty?
end
def parse_json_config(env_variable_name)
if ENV[env_variable_name].present?
begin
return JSON.parse(ENV[env_variable_name], { symbolize_names: true })
rescue StandardError
@logger.warn("Could not parse #{env_variable_name}!")
end
end
{}
end
end
end

23
app/services/configuration/paas_configuration_service.rb

@ -0,0 +1,23 @@
module Configuration
class PaasConfigurationService < ConfigurationService
private
def config_present?
!ENV["VCAP_SERVICES"].nil?
end
def read_config
unless config_present?
@logger.warn("Could not find VCAP_SERVICES in the environment variables!")
return {}
end
begin
JSON.parse(ENV["VCAP_SERVICES"], { symbolize_names: true })
rescue StandardError
@logger.warn("Could not parse VCAP_SERVICES!")
{}
end
end
end
end

9
app/services/imports/case_logs_import_service.rb

@ -107,6 +107,13 @@ module Imports
%w[a b c f g h].each do |letter|
attributes["housingneeds_#{letter}"] = housing_needs(xml_doc, letter)
end
attributes["housingneeds"] = 1 if [attributes["housingneeds_a"], attributes["housingneeds_b"], attributes["housingneeds_c"], attributes["housingneeds_f"]].any? { |housingneed| housingneed == 1 }
attributes["housingneeds"] = 2 if attributes["housingneeds_g"] == 1
attributes["housingneeds"] = 3 if attributes["housingneeds_h"] == 1
attributes["housingneeds_type"] = 0 if attributes["housingneeds_a"] == 1
attributes["housingneeds_type"] = 1 if attributes["housingneeds_b"] == 1
attributes["housingneeds_type"] = 2 if attributes["housingneeds_c"] == 1
attributes["housingneeds_other"] = attributes["housingneeds_f"] == 1 ? 1 : 0
attributes["illness"] = unsafe_string_as_integer(xml_doc, "Q10ia")
(1..10).each do |index|
@ -275,7 +282,7 @@ module Imports
end
def fields_not_present_in_softwire_data
%w[majorrepairs illness_type_0 tshortfall_known pregnancy_value_check retirement_value_check rent_value_check net_income_value_check major_repairs_date_value_check void_date_value_check]
%w[majorrepairs illness_type_0 tshortfall_known pregnancy_value_check retirement_value_check rent_value_check net_income_value_check major_repairs_date_value_check void_date_value_check housingneeds_type housingneeds_other]
end
def check_status_completed(case_log, previous_status)

62
app/services/paas_configuration_service.rb

@ -1,62 +0,0 @@
class PaasConfigurationService
attr_reader :s3_buckets, :redis_uris
def initialize(logger = Rails.logger)
@logger = logger
@paas_config = read_pass_config
@s3_buckets = read_s3_buckets
@redis_uris = read_redis_uris
end
def config_present?
!ENV["VCAP_SERVICES"].nil?
end
def s3_config_present?
config_present? && @paas_config.key?(:"aws-s3-bucket")
end
def redis_config_present?
config_present? && @paas_config.key?(:redis)
end
private
def read_pass_config
unless config_present?
@logger.warn("Could not find VCAP_SERVICES in the environment!")
return {}
end
begin
JSON.parse(ENV["VCAP_SERVICES"], { symbolize_names: true })
rescue StandardError
@logger.warn("Could not parse VCAP_SERVICES!")
{}
end
end
def read_s3_buckets
return {} unless s3_config_present?
s3_buckets = {}
@paas_config[:"aws-s3-bucket"].each do |bucket_config|
if bucket_config.key?(:instance_name)
s3_buckets[bucket_config[:instance_name].to_sym] = bucket_config
end
end
s3_buckets
end
def read_redis_uris
return {} unless redis_config_present?
redis_uris = {}
@paas_config[:redis].each do |redis_config|
if redis_config.key?(:instance_name)
redis_uris[redis_config[:instance_name].to_sym] = redis_config.dig(:credentials, :uri)
end
end
redis_uris
end
end

78
app/services/s3_storage_service.rb

@ -1,78 +0,0 @@
class S3StorageService < StorageService
attr_reader :configuration
def initialize(paas_config_service, paas_instance_name)
super()
@paas_config_service = paas_config_service
@paas_instance_name = (paas_instance_name || "").to_sym
@configuration = create_configuration
@client = create_client
end
def list_files(folder)
@client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder)
.flat_map { |response| response.contents.map(&:key) }
end
def folder_present?(folder)
response = @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder, max_keys: 1)
response.key_count == 1
end
def get_file_io(file_name)
@client.get_object(bucket: @configuration.bucket_name, key: file_name)
.body
end
def write_file(file_name, data)
@client.put_object(
body: data,
bucket: @configuration.bucket_name,
key: file_name,
)
end
private
def create_configuration
unless @paas_config_service.config_present?
raise "No PaaS configuration present"
end
unless @paas_config_service.s3_buckets.key?(@paas_instance_name)
raise "#{@paas_instance_name} instance name could not be found"
end
bucket_config = @paas_config_service.s3_buckets[@paas_instance_name]
StorageConfiguration.new(bucket_config[:credentials])
end
def create_client
credentials =
Aws::Credentials.new(
@configuration.access_key_id,
@configuration.secret_access_key,
)
Aws::S3::Client.new(
region: @configuration.region,
credentials:,
)
end
end
class StorageConfiguration
attr_reader :access_key_id, :secret_access_key, :bucket_name, :region
def initialize(credentials)
@access_key_id = credentials[:aws_access_key_id]
@secret_access_key = credentials[:aws_secret_access_key]
@bucket_name = credentials[:bucket_name]
@region = credentials[:aws_region]
end
def ==(other)
@access_key_id == other.access_key_id &&
@secret_access_key == other.secret_access_key &&
@bucket_name == other.bucket_name &&
@region == other.region
end
end

26
app/services/storage/archive_service.rb

@ -0,0 +1,26 @@
module Storage
class ArchiveService < StorageService
MAX_SIZE = 50 * (1024**2) # 50MiB
def initialize(archive_io)
super()
@archive = Zip::File.open_buffer(archive_io)
end
def list_files(folder)
@archive.glob(File.join(folder, "*.*"))
.map(&:name)
end
def folder_present?(folder)
!list_files(folder).empty?
end
def get_file_io(file_name)
entry = @archive.get_entry(file_name)
raise "File too large to be extracted" if entry.size > MAX_SIZE
entry.get_input_stream
end
end
end

80
app/services/storage/s3_service.rb

@ -0,0 +1,80 @@
module Storage
class S3Service < StorageService
attr_reader :configuration
def initialize(config_service, paas_instance_name)
super()
@config_service = config_service
@instance_name = (paas_instance_name || "").to_sym
@configuration = create_configuration
@client = create_client
end
def list_files(folder)
@client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder)
.flat_map { |response| response.contents.map(&:key) }
end
def folder_present?(folder)
response = @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder, max_keys: 1)
response.key_count == 1
end
def get_file_io(file_name)
@client.get_object(bucket: @configuration.bucket_name, key: file_name)
.body
end
def write_file(file_name, data)
@client.put_object(
body: data,
bucket: @configuration.bucket_name,
key: file_name,
)
end
private
def create_configuration
unless @config_service.s3_config_present?
raise "No S3 bucket is present in the PaaS configuration"
end
unless @config_service.s3_buckets.key?(@instance_name)
raise "#{@instance_name} instance name could not be found"
end
bucket_config = @config_service.s3_buckets[@instance_name]
StorageConfiguration.new(bucket_config[:credentials])
end
def create_client
credentials =
Aws::Credentials.new(
@configuration.access_key_id,
@configuration.secret_access_key,
)
Aws::S3::Client.new(
region: @configuration.region,
credentials:,
)
end
end
class StorageConfiguration
attr_reader :access_key_id, :secret_access_key, :bucket_name, :region
def initialize(credentials)
@access_key_id = credentials[:aws_access_key_id]
@secret_access_key = credentials[:aws_secret_access_key]
@bucket_name = credentials[:bucket_name]
@region = credentials[:aws_region]
end
def ==(other)
@access_key_id == other.access_key_id &&
@secret_access_key == other.secret_access_key &&
@bucket_name == other.bucket_name &&
@region == other.region
end
end
end

19
app/services/storage/storage_service.rb

@ -0,0 +1,19 @@
module Storage
class StorageService
def list_files(_folder)
raise NotImplementedError
end
def folder_present?(_folder)
raise NotImplementedError
end
def get_file_io(_file_name)
raise NotImplementedError
end
def write_file(_file_name, _data)
raise NotImplementedError
end
end
end

17
app/services/storage_service.rb

@ -1,17 +0,0 @@
class StorageService
def list_files(_folder)
raise NotImplementedError
end
def folder_present?(_folder)
raise NotImplementedError
end
def get_file_io(_file_name)
raise NotImplementedError
end
def write_file(_file_name, _data)
raise NotImplementedError
end
end

76
config/forms/2021_2022.json

@ -790,7 +790,7 @@
}
]
},
"header": "Are you sure the time between these dates is correct?",
"header": "Are you sure the property has been vacant for this long?",
"type": "interruption_screen",
"answer_options": {
"0": {
@ -919,7 +919,7 @@
}
]
},
"header": "Are you sure the time between these dates is correct?",
"header": "Are you sure the property has been vacant for this long?",
"type": "interruption_screen",
"answer_options": {
"0": {
@ -5667,40 +5667,79 @@
}
}
},
"access_needs": {
"access_needs_exist": {
"header": "",
"description": "",
"questions": {
"accessibility_requirements": {
"housingneeds": {
"header": "Does anybody in the household have any disabled access needs?",
"hint_text": "",
"type": "checkbox",
"check_answer_label": "Anybody in household with disabled access needs",
"type": "radio",
"check_answer_label": "Anybody with disabled access needs",
"answer_options": {
"1": {
"value": "Yes"
},
"2": {
"value": "No"
},
"divider": {
"value": true
},
"3": {
"value": "Don’t know"
}
}
}
}
},
"type_of_access_needs": {
"header": "Disabled access needs",
"description": "",
"questions": {
"housingneeds_type": {
"header": "What type of access need do they have?",
"hint_text": "",
"type": "radio",
"check_answer_label": "Disabled access needs",
"answer_options": {
"housingneeds_a": {
"0": {
"value": "Fully wheelchair accessible housing"
},
"housingneeds_b": {
"1": {
"value": "Wheelchair access to essential rooms"
},
"housingneeds_c": {
"2": {
"value": "Level access housing"
},
"housingneeds_f": {
"value": "Other disabled access needs"
},
"divider": {
"value": true
},
"housingneeds_g": {
"value": "No disabled access needs"
"3": {
"value": "None of the above"
}
}
},
"housingneeds_h": {
"value": "Don’t know"
"housingneeds_other": {
"header": "Do they have any other access needs?",
"hint_text": "",
"type": "radio",
"check_answer_label": "Other disabled access needs",
"answer_options": {
"1": {
"value": "Yes"
},
"0": {
"value": "No"
}
}
}
},
"depends_on": [
{
"housingneeds": 1
}
]
},
"health_conditions": {
"header": "",
@ -6209,12 +6248,7 @@
}
}
}
},
"depends_on": [
{
"renewal": 0
}
]
},
"previous_postcode": {
"header": "",

76
config/forms/2022_2023.json

@ -790,7 +790,7 @@
}
]
},
"header": "Are you sure the time between these dates is correct?",
"header": "Are you sure the property has been vacant for this long?",
"type": "interruption_screen",
"answer_options": {
"0": {
@ -919,7 +919,7 @@
}
]
},
"header": "Are you sure the time between these dates is correct?",
"header": "Are you sure the property has been vacant for this long?",
"type": "interruption_screen",
"answer_options": {
"0": {
@ -5669,40 +5669,79 @@
}
}
},
"access_needs": {
"access_needs_exist": {
"header": "",
"description": "",
"questions": {
"accessibility_requirements": {
"housingneeds": {
"header": "Does anybody in the household have any disabled access needs?",
"hint_text": "",
"type": "checkbox",
"check_answer_label": "Anybody in household with disabled access needs",
"type": "radio",
"check_answer_label": "Anybody with disabled access needs",
"answer_options": {
"1": {
"value": "Yes"
},
"2": {
"value": "No"
},
"divider": {
"value": true
},
"3": {
"value": "Don’t know"
}
}
}
}
},
"type_of_access_needs": {
"header": "Disabled access needs",
"description": "",
"questions": {
"housingneeds_type": {
"header": "What type of access need do they have?",
"hint_text": "",
"type": "radio",
"check_answer_label": "Disabled access needs",
"answer_options": {
"housingneeds_a": {
"0": {
"value": "Fully wheelchair accessible housing"
},
"housingneeds_b": {
"1": {
"value": "Wheelchair access to essential rooms"
},
"housingneeds_c": {
"2": {
"value": "Level access housing"
},
"housingneeds_f": {
"value": "Other disabled access needs"
},
"divider": {
"value": true
},
"housingneeds_g": {
"value": "No disabled access needs"
"3": {
"value": "None of the above"
}
}
},
"housingneeds_h": {
"value": "Don’t know"
"housingneeds_other": {
"header": "Do they have any other access needs?",
"hint_text": "",
"type": "radio",
"check_answer_label": "Other disabled access needs",
"answer_options": {
"1": {
"value": "Yes"
},
"0": {
"value": "No"
}
}
}
},
"depends_on": [
{
"housingneeds": 1
}
]
},
"health_conditions": {
"header": "",
@ -6168,12 +6207,7 @@
}
}
}
},
"depends_on": [
{
"renewal": 0
}
]
},
"previous_postcode": {
"header": "",

5
config/initializers/rack_attack.rb

@ -1,10 +1,11 @@
require "paas_configuration_service"
require "configuration/configuration_service"
require "configuration/paas_configuration_service"
if Rails.env.development? || Rails.env.test?
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
Rack::Attack.enabled = false
else
redis_url = PaasConfigurationService.new.redis_uris[:"dluhc-core-#{Rails.env}-redis-rate-limit"]
redis_url = Configuration::PaasConfigurationService.new.redis_uris[:"dluhc-core-#{Rails.env}-redis-rate-limit"]
Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(url: redis_url)
end

4
config/locales/en.yml

@ -124,8 +124,8 @@ en:
not_first_let: "Major repairs date must not be completed if the tenancy is a first let"
ten_years_before_tenancy_start: "Enter a major repairs completion date that is no more than 10 years before the tenancy start date"
void_date:
ten_years_before_tenancy_start: "Enter a void date must no more than 10 years before the tenancy start date"
before_tenancy_start: "Enter a void date must that is before the tenancy start date"
ten_years_before_tenancy_start: "Enter a void date no more than 10 years before the tenancy start date"
before_tenancy_start: "Enter a void date that is before the tenancy start date"
after_mrcdate: "Void date must be before the major repairs date if provided"
offered:
relet_number: "Enter a number between 0 and 20 for the amount of times the property has been re-let"

8
db/migrate/20220809100723_add_accessibility_requirements_fields.rb

@ -0,0 +1,8 @@
class AddAccessibilityRequirementsFields < ActiveRecord::Migration[7.0]
def change
change_table :case_logs, bulk: true do |t|
t.column :housingneeds_type, :integer
t.column :housingneeds_other, :integer
end
end
end

43
docs/infrastructure.md

@ -4,6 +4,49 @@ nav_order: 5
# Infrastructure
## Configuration
On [GOV.UK PaaS](https://www.cloud.service.gov.uk/), service credentials are appended to the environment variable `VCAP_SERVICES` when services [are bound](https://docs.cloud.service.gov.uk/deploying_services/s3/#bind-an-aws-s3-bucket-to-your-app) to an application.
Such services include datastores and S3 buckets.
Our application uses S3 and Redis clients and supports two different ways of parsing their configuration:
* Via the environment variable `VCAP_SERVICES` using the `PaasConfigurationService` class
* Via the environment variables `S3_CONFIG` and `REDIS_CONFIG` using the `EnvConfigurationService` class
`S3_CONFIG` and `REDIS_CONFIG` are populated using a similar structure than `VCAP_SERVICES`:
S3_CONFIG:
```json
[
{
"instance_name": "bucket_1",
"credentials": {
"aws_access_key_id": "123",
"aws_secret_access_key": "456",
"aws_region": "eu-west-1",
"bucket_name": "my-bucket"
}
}
]
```
REDIS_CONFIG:
```json
[
{
"instance_name": "redis_1",
"credentials": {
"uri": "redis_uri"
}
}
]
```
In order to switch from using [GOV.UK PaaS](https://www.cloud.service.gov.uk/) provided services to external ones, instances of `PaasConfigurationService` need to be replaced by `EnvConfigurationService`.
This assumes that `S3_CONFIG` or/and `REDIS_CONFIG` are available.
Please check `full_import.rake` and `rack_attack.rb` for examples of how the configuration is used.
## Deployment
This application is running on [GOV.UK PaaS](https://www.cloud.service.gov.uk/). To deploy you need to:

2
lib/tasks/data_export.rake

@ -4,7 +4,7 @@ namespace :core do
format = args[:format]
full_update = args[:full_update].present? && args[:full_update] == "true"
storage_service = S3StorageService.new(PaasConfigurationService.new, ENV["EXPORT_PAAS_INSTANCE"])
storage_service = Storage::S3Service.new(Configuration::PaasConfigurationService.new, ENV["EXPORT_PAAS_INSTANCE"])
export_service = Exports::CaseLogExportService.new(storage_service)
if format.present? && format == "CSV"

2
lib/tasks/data_import.rake

@ -5,7 +5,7 @@ namespace :core do
path = args[:path]
raise "Usage: rake core:data_import['data_type', 'path/to/xml_files']" if path.blank? || type.blank?
storage_service = S3StorageService.new(PaasConfigurationService.new, ENV["IMPORT_PAAS_INSTANCE"])
storage_service = Storage::S3Service.new(Configuration::PaasConfigurationService.new, ENV["IMPORT_PAAS_INSTANCE"])
case type
when "organisation"

2
lib/tasks/data_import_field.rake

@ -5,7 +5,7 @@ namespace :core do
path = args[:path]
raise "Usage: rake core:data_import_field['field','path/to/xml_files']" if path.blank? || field.blank?
storage_service = S3StorageService.new(PaasConfigurationService.new, ENV["IMPORT_PAAS_INSTANCE"])
storage_service = Storage::S3Service.new(Configuration::PaasConfigurationService.new, ENV["IMPORT_PAAS_INSTANCE"])
# We only allow a reduced list of known fields to be updatable
case field

4
lib/tasks/full_import.rake

@ -6,9 +6,9 @@ namespace :core do
archive_path = args[:archive_path]
raise "Usage: rake core:full_import['path/to/archive']" if archive_path.blank?
s3_service = S3StorageService.new(PaasConfigurationService.new, ENV["IMPORT_PAAS_INSTANCE"])
s3_service = Storage::S3Service.new(Configuration::PaasConfigurationService.new, ENV["IMPORT_PAAS_INSTANCE"])
archive_io = s3_service.get_file_io(archive_path)
archive_service = ArchiveStorageService.new(archive_io)
archive_service = Storage::ArchiveService.new(archive_io)
import_list = [
Import.new(Imports::OrganisationImportService, :create_organisations, "institution"),

3
spec/factories/case_log.rb

@ -87,6 +87,9 @@ FactoryBot.define do
chr { 1 }
cap { 0 }
reasonother { nil }
housingneeds { 1 }
housingneeds_type { 0 }
housingneeds_other { 0 }
housingneeds_a { 1 }
housingneeds_b { 0 }
housingneeds_c { 0 }

16
spec/features/form/checkboxes_spec.rb

@ -41,24 +41,24 @@ RSpec.describe "Checkboxes" do
context "when a checkbox question is submitted with invalid answers" do
before do
case_log.update!(illness: 100)
allow(case_log).to receive(:update).and_return(false)
end
it "shows an error summary" do
visit("/logs/#{id}/accessibility-requirements")
page.check("case-log-accessibility-requirements-housingneeds-a-field")
page.check("case-log-accessibility-requirements-housingneeds-c-field")
visit("/logs/#{id}/condition-effects")
page.check("case-log-condition-effects-illness-type-1-field")
page.check("case-log-condition-effects-illness-type-2-field")
click_button("Save and continue")
expect(page).to have_title("Error")
end
it "persists the original selections" do
visit("/logs/#{id}/accessibility-requirements")
page.check("case-log-accessibility-requirements-housingneeds-a-field")
page.check("case-log-accessibility-requirements-housingneeds-c-field")
visit("/logs/#{id}/condition-effects")
page.check("case-log-condition-effects-illness-type-1-field")
page.check("case-log-condition-effects-illness-type-2-field")
click_button("Save and continue")
expect(page).to have_checked_field("case-log-accessibility-requirements-housingneeds-a-field")
expect(page).to have_checked_field("case-log-accessibility-requirements-housingneeds-c-field")
expect(page).to have_checked_field("case-log-condition-effects-illness-type-2-field")
end
end
end

9
spec/fixtures/complete_case_log.json vendored

@ -56,12 +56,10 @@
"chr":0,
"cap":0,
"reasonother":"",
"housingneeds_a":0,
"housingneeds_b":0,
"housingneeds": 1,
"housingneeds_type": 2,
"housingneeds_other": 0,
"housingneeds_c": 1,
"housingneeds_f":0,
"housingneeds_g":0,
"housingneeds_h":0,
"illness_type_1":null,
"illness_type_2":null,
"illness_type_3":null,
@ -155,7 +153,6 @@
"wtcharge":"93.0",
"wtshortfall":null,
"refused":1,
"housingneeds":2,
"wchchrg":null,
"newprop":2,
"relat2":"P",

48
spec/fixtures/forms/2021_2022.json vendored

@ -390,6 +390,9 @@
"depends_on": [
{
"illness": 1
},
{
"illness": 100
}
]
}
@ -634,10 +637,12 @@
"label": true,
"i18n_template": "ecstat1"
},
{"key": "earnings",
{
"key": "earnings",
"label": true,
"i18n_template": "earnings"
}]
}
]
},
"questions": {
"net_income_value_check": {
@ -752,12 +757,7 @@
"min": 0,
"step": 1,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"scharge": {
@ -768,12 +768,7 @@
"min": 0,
"step": 1,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"pscharge": {
@ -784,12 +779,7 @@
"min": 0,
"step": 1,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"supcharg": {
@ -801,12 +791,7 @@
"max": 300,
"step": 1,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"tcharge": {
@ -913,10 +898,7 @@
}
},
"hidden_in_check_answers": {
"depends_on": [
{ "layear": 0 },
{ "layear": 1 }
]
"depends_on": [{ "layear": 0 }, { "layear": 1 }]
}
}
},
@ -998,11 +980,13 @@
"subsections": {
"declaration": {
"label": "Declaration",
"depends_on": [{
"depends_on": [
{
"household_characteristics": "completed",
"household_needs": "completed",
"property_information": "completed"
}],
}
],
"pages": {
"declaration": {
"questions": {

12
spec/lib/tasks/data_export_spec.rb

@ -5,8 +5,8 @@ describe "rake core:data_export", type: task do
subject(:task) { Rake::Task["core:data_export"] }
let(:paas_instance) { "paas_export_instance" }
let(:storage_service) { instance_double(S3StorageService) }
let(:paas_config_service) { instance_double(PaasConfigurationService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:paas_config_service) { instance_double(Configuration::PaasConfigurationService) }
let(:export_service) { instance_double(Exports::CaseLogExportService) }
before do
@ -14,8 +14,8 @@ describe "rake core:data_export", type: task do
Rake::Task.define_task(:environment)
task.reenable
allow(S3StorageService).to receive(:new).and_return(storage_service)
allow(PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(Storage::S3Service).to receive(:new).and_return(storage_service)
allow(Configuration::PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(Exports::CaseLogExportService).to receive(:new).and_return(export_service)
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("EXPORT_PAAS_INSTANCE").and_return(paas_instance)
@ -23,7 +23,7 @@ describe "rake core:data_export", type: task do
context "when exporting case logs with no parameters" do
it "starts the XML export process" do
expect(S3StorageService).to receive(:new).with(paas_config_service, paas_instance)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, paas_instance)
expect(Exports::CaseLogExportService).to receive(:new).with(storage_service)
expect(export_service).to receive(:export_xml_case_logs)
@ -33,7 +33,7 @@ describe "rake core:data_export", type: task do
context "when exporting case logs with CSV format" do
it "starts the CSV export process" do
expect(S3StorageService).to receive(:new).with(paas_config_service, paas_instance)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, paas_instance)
expect(Exports::CaseLogExportService).to receive(:new).with(storage_service)
expect(export_service).to receive(:export_csv_case_logs)

22
spec/lib/tasks/data_import_spec.rb

@ -5,16 +5,16 @@ describe "rake core:data_import", type: :task do
subject(:task) { Rake::Task["core:data_import"] }
let(:instance_name) { "paas_import_instance" }
let(:storage_service) { instance_double(S3StorageService) }
let(:paas_config_service) { instance_double(PaasConfigurationService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:paas_config_service) { instance_double(Configuration::PaasConfigurationService) }
before do
Rake.application.rake_require("tasks/data_import")
Rake::Task.define_task(:environment)
task.reenable
allow(S3StorageService).to receive(:new).and_return(storage_service)
allow(PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(Storage::S3Service).to receive(:new).and_return(storage_service)
allow(Configuration::PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("IMPORT_PAAS_INSTANCE").and_return(instance_name)
end
@ -29,7 +29,7 @@ describe "rake core:data_import", type: :task do
end
it "creates an organisation from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::OrganisationImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_organisations).with(fixture_path)
@ -47,7 +47,7 @@ describe "rake core:data_import", type: :task do
end
it "creates a user from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::UserImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_users).with(fixture_path)
@ -65,7 +65,7 @@ describe "rake core:data_import", type: :task do
end
it "creates an organisation from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::DataProtectionConfirmationImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_data_protection_confirmations).with(fixture_path)
@ -83,7 +83,7 @@ describe "rake core:data_import", type: :task do
end
it "creates an organisation la from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::OrganisationRentPeriodImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_organisation_rent_periods).with(fixture_path)
@ -101,7 +101,7 @@ describe "rake core:data_import", type: :task do
end
it "creates case logs from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::CaseLogsImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_logs).with(fixture_path)
@ -119,7 +119,7 @@ describe "rake core:data_import", type: :task do
end
it "creates a scheme from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::SchemeImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_schemes).with(fixture_path)
@ -137,7 +137,7 @@ describe "rake core:data_import", type: :task do
end
it "creates a scheme location from the given XML file" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
expect(Imports::SchemeLocationImportService).to receive(:new).with(storage_service)
expect(import_service).to receive(:create_scheme_locations).with(fixture_path)

14
spec/lib/tasks/date_import_field_spec.rb

@ -5,16 +5,16 @@ describe "rake core:data_import_field", type: :task do
subject(:task) { Rake::Task["core:data_import_field"] }
let(:instance_name) { "paas_import_instance" }
let(:storage_service) { instance_double(S3StorageService) }
let(:paas_config_service) { instance_double(PaasConfigurationService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:paas_config_service) { instance_double(Configuration::PaasConfigurationService) }
before do
Rake.application.rake_require("tasks/data_import_field")
Rake::Task.define_task(:environment)
task.reenable
allow(S3StorageService).to receive(:new).and_return(storage_service)
allow(PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(Storage::S3Service).to receive(:new).and_return(storage_service)
allow(Configuration::PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("IMPORT_PAAS_INSTANCE").and_return(instance_name)
end
@ -32,7 +32,7 @@ describe "rake core:data_import_field", type: :task do
let(:field) { "tenant_code" }
it "properly configures the storage service" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
task.invoke(field, fixture_path)
end
@ -46,7 +46,7 @@ describe "rake core:data_import_field", type: :task do
let(:field) { "lettings_allocation" }
it "properly configures the storage service" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
task.invoke(field, fixture_path)
end
@ -60,7 +60,7 @@ describe "rake core:data_import_field", type: :task do
let(:field) { "major_repairs" }
it "properly configures the storage service" do
expect(S3StorageService).to receive(:new).with(paas_config_service, instance_name)
expect(Storage::S3Service).to receive(:new).with(paas_config_service, instance_name)
task.invoke(field, fixture_path)
end

12
spec/lib/tasks/full_import_spec.rb

@ -5,19 +5,19 @@ require "zip"
describe "rake core:full_import", type: :task do
subject(:task) { Rake::Task["core:full_import"] }
let(:s3_service) { instance_double(S3StorageService) }
let(:archive_service) { instance_double(ArchiveStorageService) }
let(:paas_config_service) { instance_double(PaasConfigurationService) }
let(:s3_service) { instance_double(Storage::S3Service) }
let(:archive_service) { instance_double(Storage::ArchiveService) }
let(:paas_config_service) { instance_double(Configuration::PaasConfigurationService) }
before do
Rake.application.rake_require("tasks/full_import")
Rake::Task.define_task(:environment)
task.reenable
allow(PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(S3StorageService).to receive(:new).and_return(s3_service)
allow(Configuration::PaasConfigurationService).to receive(:new).and_return(paas_config_service)
allow(Storage::S3Service).to receive(:new).and_return(s3_service)
allow(s3_service).to receive(:get_file_io)
allow(ArchiveStorageService).to receive(:new).and_return(archive_service)
allow(Storage::ArchiveService).to receive(:new).and_return(archive_service)
end
context "when starting a full import" do

125
spec/models/case_log_spec.rb

@ -139,10 +139,6 @@ RSpec.describe CaseLog do
expect(validator).to receive(:validate_rsnvac)
end
it "validates accessibility requirements" do
expect(validator).to receive(:validate_accessibility_requirements)
end
it "validates referral" do
expect(validator).to receive(:validate_referral)
end
@ -1440,34 +1436,6 @@ RSpec.describe CaseLog do
end
end
context "when the data provider is filling in household needs" do
let!(:case_log) do
described_class.create({
managing_organisation: owning_organisation,
owning_organisation:,
created_by: created_by_user,
})
end
it "correctly derives and saves housing neeeds as 1" do
case_log.update!(housingneeds_a: 1)
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds from case_logs where id=#{case_log.id}").to_a[0]
expect(record_from_db["housingneeds"]).to eq(1)
end
it "correctly derives and saves housing neeeds as 2" do
case_log.update!(housingneeds_g: 1)
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds from case_logs where id=#{case_log.id}").to_a[0]
expect(record_from_db["housingneeds"]).to eq(2)
end
it "correctly derives and saves housing neeeds as 3" do
case_log.update!(housingneeds_h: 1)
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds from case_logs where id=#{case_log.id}").to_a[0]
expect(record_from_db["housingneeds"]).to eq(3)
end
end
context "when it is supported housing and a care home charge has been supplied" do
let!(:case_log) do
described_class.create({
@ -1753,6 +1721,99 @@ RSpec.describe CaseLog do
end
end
end
context "when saving accessibility needs" do
it "derives housingneeds_h as true if 'Don't know' is selected for housingneeds" do
case_log.update!({ housingneeds: 3 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_h"]).to eq(1)
expect(case_log["housingneeds_h"]).to eq(1)
end
it "derives housingneeds_g as true if 'No' is selected for housingneeds" do
case_log.update!({ housingneeds: 2 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_h]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_g"]).to eq(1)
expect(case_log["housingneeds_g"]).to eq(1)
end
it "derives housingneeds_a as true if 'Fully wheelchair accessible' is selected for housingneeds_type" do
case_log.update!({ housingneeds: 1, housingneeds_type: 0 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_a"]).to eq(1)
expect(case_log["housingneeds_a"]).to eq(1)
end
it "derives housingneeds_b as true if 'Wheelchair access to essential rooms' is selected for housingneeds_type" do
case_log.update!({ housingneeds: 1, housingneeds_type: 1 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_a housingneeds_c housingneeds_f housingneeds_g housingneeds_h]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_b"]).to eq(1)
expect(case_log["housingneeds_b"]).to eq(1)
end
it "derives housingneeds_c if 'Level access housing' is selected for housingneeds_type" do
case_log.update!({ housingneeds: 1, housingneeds_type: 2 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_a housingneeds_b housingneeds_f housingneeds_g housingneeds_h]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_c"]).to eq(1)
expect(case_log["housingneeds_c"]).to eq(1)
end
it "derives housingneeds_f if 'Yes' is selected for housingneeds_other" do
case_log.update!({ housingneeds: 1, housingneeds_other: 1 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_a housingneeds_b housingneeds_c housingneeds_g housingneeds_h]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_f"]).to eq(1)
expect(case_log["housingneeds_f"]).to eq(1)
end
it "clears previously set housingneeds if 'No' is selected for housingneeds" do
case_log.update!({ housingneeds: 1, housingneeds_type: 2, housingneeds_other: 1 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
expect(record_from_db["housingneeds_c"]).to eq(1)
expect(case_log["housingneeds_c"]).to eq(1)
expect(record_from_db["housingneeds_f"]).to eq(1)
expect(case_log["housingneeds_f"]).to eq(1)
case_log.update!({ housingneeds: 2 })
record_from_db = ActiveRecord::Base.connection.execute("select housingneeds_a, housingneeds_b, housingneeds_c, housingneeds_f, housingneeds_g, housingneeds_h from case_logs where id=#{case_log.id}").to_a[0]
not_selected_housingneeds = %w[housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_h]
not_selected_housingneeds.each do |housingneed|
expect(record_from_db[housingneed]).to eq(0)
expect(case_log[housingneed]).to eq(0)
end
expect(record_from_db["housingneeds_g"]).to eq(1)
expect(case_log["housingneeds_g"]).to eq(1)
end
end
end
describe "optional fields" do

40
spec/models/validations/household_validations_spec.rb

@ -575,46 +575,6 @@ RSpec.describe Validations::HouseholdValidations do
end
end
describe "accessibility requirement validations" do
it "validates that mutually exclusive options can't be selected together" do
record.housingneeds_a = 1
record.housingneeds_b = 1
household_validator.validate_accessibility_requirements(record)
expect(record.errors["accessibility_requirements"])
.to include(match I18n.t("validations.household.housingneeds_a.one_or_two_choices"))
record.housingneeds_a = 0
record.housingneeds_b = 0
record.housingneeds_g = 1
record.housingneeds_f = 1
household_validator.validate_accessibility_requirements(record)
expect(record.errors["accessibility_requirements"])
.to include(match I18n.t("validations.household.housingneeds_a.one_or_two_choices"))
record.housingneeds_a = 1
record.housingneeds_g = 1
record.housingneeds_f = 1
household_validator.validate_accessibility_requirements(record)
expect(record.errors["accessibility_requirements"])
.to include(match I18n.t("validations.household.housingneeds_a.one_or_two_choices"))
end
it "validates that non-mutually exclusive options can be selected together" do
record.housingneeds_a = 1
record.housingneeds_f = 1
household_validator.validate_accessibility_requirements(record)
expect(record.errors["accessibility_requirements"]).to be_empty
record.housingneeds_a = 0
record.housingneeds_b = 1
record.housingneeds_f = 1
household_validator.validate_accessibility_requirements(record)
expect(record.errors["accessibility_requirements"]).to be_empty
record.housingneeds_b = 0
record.housingneeds_c = 1
record.housingneeds_f = 1
household_validator.validate_accessibility_requirements(record)
expect(record.errors["accessibility_requirements"]).to be_empty
end
end
describe "referral validations" do
context "when homelessness is assessed" do
it "can be internal transfer" do

128
spec/services/configuration/env_configuration_service_spec.rb

@ -0,0 +1,128 @@
require "rails_helper"
RSpec.describe Configuration::EnvConfigurationService do
subject(:config_service) { described_class.new(logger) }
let(:logger) { instance_double(ActiveSupport::LogSubscriber) }
context "when environment configurations are unavailable" do
before { allow(logger).to receive(:warn) }
it "returns the S3 configuration as not present" do
expect(config_service.s3_config_present?).to be(false)
end
it "returns the redis configuration as not present" do
expect(config_service.redis_config_present?).to be(false)
end
it "does not retrieve any S3 bucket configuration" do
expect(config_service.s3_buckets).to be_a(Hash)
expect(config_service.s3_buckets).to be_empty
end
it "does not retrieve any redis configuration" do
expect(config_service.redis_uris).to be_a(Hash)
expect(config_service.redis_uris).to be_empty
end
end
context "when environment configurations are present but invalid" do
let(:env_variable) { "random text" }
before do
allow(ENV).to receive(:[]).with("S3_CONFIG").and_return(env_variable)
allow(ENV).to receive(:[]).with("REDIS_CONFIG").and_return(env_variable)
allow(logger).to receive(:warn)
end
it "logs an error when checking if the S3 config is present" do
expect(logger).to receive(:warn).with("Could not parse S3_CONFIG!")
config_service.s3_config_present?
end
it "logs an error when checking if the Redis config is present" do
expect(logger).to receive(:warn).with("Could not parse REDIS_CONFIG!")
config_service.redis_config_present?
end
end
context "when environment configurations are present with S3 configured" do
let(:s3_config) do
<<~JSON
[
{
"instance_name": "bucket_1",
"credentials": {
"aws_access_key_id": "123",
"aws_secret_access_key": "456",
"aws_region": "eu-west-1",
"bucket_name": "my-bucket"
}
},
{
"instance_name": "bucket_2",
"credentials": {
"aws_access_key_id": "789",
"aws_secret_access_key": "012",
"aws_region": "eu-west-2",
"bucket_name": "my-bucket2"
}
}
]
JSON
end
before do
allow(ENV).to receive(:[]).with("REDIS_CONFIG")
allow(ENV).to receive(:[]).with("S3_CONFIG").and_return(s3_config)
end
it "returns the S3 configuration as present" do
expect(config_service.s3_config_present?).to be(true)
end
it "returns the redis configuration as not present" do
expect(config_service.redis_config_present?).to be(false)
end
it "does retrieve the S3 bucket configurations" do
s3_buckets = config_service.s3_buckets
expect(s3_buckets).not_to be_empty
expect(s3_buckets.count).to be(2)
expect(s3_buckets).to have_key(:bucket_1)
expect(s3_buckets).to have_key(:bucket_2)
end
end
context "when environment configurations are present with redis configured" do
let(:redis_config) do
<<-JSON
[{"instance_name": "redis_1", "credentials": {"uri": "redis_uri" }}]
JSON
end
before do
allow(ENV).to receive(:[]).with("S3_CONFIG")
allow(ENV).to receive(:[]).with("REDIS_CONFIG").and_return(redis_config)
end
it "returns the redis configuration as present" do
expect(config_service.redis_config_present?).to be(true)
end
it "returns the S3 configuration as not present" do
expect(config_service.s3_config_present?).to be(false)
end
it "does retrieve the redis configurations" do
redis_uris = config_service.redis_uris
expect(redis_uris).not_to be_empty
expect(redis_uris.count).to be(1)
expect(redis_uris).to have_key(:redis_1)
expect(redis_uris[:redis_1]).to eq("redis_uri")
end
end
end

120
spec/services/paas_configuration_service_spec.rb → spec/services/configuration/paas_configuration_service_spec.rb

@ -1,6 +1,6 @@
require "rails_helper"
RSpec.describe PaasConfigurationService do
RSpec.describe Configuration::PaasConfigurationService do
subject(:config_service) { described_class.new(logger) }
let(:logger) { instance_double(ActiveSupport::LogSubscriber) }
@ -8,14 +8,38 @@ RSpec.describe PaasConfigurationService do
context "when the paas configuration is unavailable" do
before { allow(logger).to receive(:warn) }
it "returns the configuration as not present" do
expect(config_service.config_present?).to be(false)
it "returns the S3 configuration as not present" do
expect(config_service.s3_config_present?).to be(false)
end
it "returns the redis configuration as not present" do
expect(config_service.redis_config_present?).to be(false)
end
it "does not retrieve any S3 bucket configuration" do
expect(config_service.s3_buckets).to be_a(Hash)
expect(config_service.s3_buckets).to be_empty
end
it "does not retrieve any redis configuration" do
expect(config_service.redis_uris).to be_a(Hash)
expect(config_service.redis_uris).to be_empty
end
end
context "when the paas configuration is present but empty" do
before do
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return("{}")
end
it "returns the S3 configuration as not present" do
expect(config_service.s3_config_present?).to be(false)
end
it "returns the redis configuration as not present" do
expect(config_service.redis_config_present?).to be(false)
end
it "does not retrieve any S3 bucket configuration" do
expect(config_service.s3_buckets).to be_a(Hash)
expect(config_service.s3_buckets).to be_empty
@ -27,7 +51,7 @@ RSpec.describe PaasConfigurationService do
end
end
context "when configuration is present but invalid" do
context "when the paas configuration is present but invalid" do
let(:vcap_services) { "random text" }
before do
@ -35,16 +59,40 @@ RSpec.describe PaasConfigurationService do
allow(logger).to receive(:warn)
end
it "logs an error" do
it "logs an error when checking if the S3 config is present" do
expect(logger).to receive(:warn).with("Could not parse VCAP_SERVICES!")
config_service.s3_config_present?
end
it "logs an error when checking if the Redis config is present" do
expect(logger).to receive(:warn).with("Could not parse VCAP_SERVICES!")
config_service.redis_config_present?
end
end
context "when the paas configuration is present with S3 buckets" do
context "when the paas configuration is present with S3 configured" do
let(:vcap_services) do
<<-JSON
{"aws-s3-bucket": [{"instance_name": "bucket_1"},{"instance_name": "bucket_2"}]}
<<~JSON
{"aws-s3-bucket":
[{
"instance_name": "bucket_1",
"credentials": {
"aws_access_key_id": "123",
"aws_secret_access_key": "456",
"aws_region": "eu-west-1",
"bucket_name": "my-bucket"
}
},
{
"instance_name": "bucket_2",
"credentials": {
"aws_access_key_id": "789",
"aws_secret_access_key": "012",
"aws_region": "eu-west-2",
"bucket_name": "my-bucket2"
}
}]
}
JSON
end
@ -52,14 +100,14 @@ RSpec.describe PaasConfigurationService do
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services)
end
it "returns the configuration as present" do
expect(config_service.config_present?).to be(true)
end
it "returns the S3 configuration as present" do
expect(config_service.s3_config_present?).to be(true)
end
it "returns the redis configuration as not present" do
expect(config_service.redis_config_present?).to be(false)
end
it "does retrieve the S3 bucket configurations" do
s3_buckets = config_service.s3_buckets
@ -70,26 +118,7 @@ RSpec.describe PaasConfigurationService do
end
end
context "when the paas configuration is present without S3 buckets" do
before do
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return("{}")
end
it "returns the configuration as present" do
expect(config_service.config_present?).to be(true)
end
it "returns the S3 configuration as not present" do
expect(config_service.s3_config_present?).to be(false)
end
it "does not retrieve any S3 bucket configuration" do
expect(config_service.s3_buckets).to be_a(Hash)
expect(config_service.s3_buckets).to be_empty
end
end
context "when the paas configuration is present with redis configurations" do
context "when the paas configuration is present with redis configured" do
let(:vcap_services) do
<<-JSON
{"redis": [{"instance_name": "redis_1", "credentials": {"uri": "redis_uri" }}]}
@ -100,14 +129,14 @@ RSpec.describe PaasConfigurationService do
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services)
end
it "returns the configuration as present" do
expect(config_service.config_present?).to be(true)
end
it "returns the redis configuration as present" do
expect(config_service.redis_config_present?).to be(true)
end
it "returns the S3 configuration as not present" do
expect(config_service.s3_config_present?).to be(false)
end
it "does retrieve the redis configurations" do
redis_uris = config_service.redis_uris
@ -117,23 +146,4 @@ RSpec.describe PaasConfigurationService do
expect(redis_uris[:redis_1]).to eq("redis_uri")
end
end
context "when the paas configuration is present without redis configuration" do
before do
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return("{}")
end
it "returns the configuration as present" do
expect(config_service.config_present?).to be(true)
end
it "returns the redis configuration as not present" do
expect(config_service.redis_config_present?).to be(false)
end
it "does not retrieve any redis uris from configuration" do
expect(config_service.redis_uris).to be_a(Hash)
expect(config_service.redis_uris).to be_empty
end
end
end

18
spec/services/csv/case_log_csv_service_spec.rb

@ -105,12 +105,9 @@ RSpec.describe Csv::CaseLogCsvService do
leftreg
reservist
preg_occ
housingneeds_a
housingneeds_b
housingneeds_c
housingneeds_f
housingneeds_g
housingneeds_h
housingneeds
housingneeds_type
housingneeds_other
illness
illness_type_4
illness_type_5
@ -165,6 +162,12 @@ RSpec.describe Csv::CaseLogCsvService do
hbrentshortfall
tshortfall_known
tshortfall
housingneeds_a
housingneeds_b
housingneeds_c
housingneeds_f
housingneeds_g
housingneeds_h
property_owner_organisation
property_manager_organisation
sale_or_letting
@ -187,7 +190,6 @@ RSpec.describe Csv::CaseLogCsvService do
wtcharge
wtshortfall
refused
housingneeds
wchchrg
newprop
old_form_id
@ -198,8 +200,6 @@ RSpec.describe Csv::CaseLogCsvService do
hhtype
new_old
vacdays
housingneeds_type
housingneeds_other
unittype_sh
scheme_code
scheme_service_name

2
spec/services/exports/case_log_export_service_spec.rb

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe Exports::CaseLogExportService do
subject(:export_service) { described_class.new(storage_service) }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:xml_export_file) { File.open("spec/fixtures/exports/general_needs_log.xml", "r:UTF-8") }
let(:local_manifest_file) { File.open("spec/fixtures/exports/manifest.xml", "r:UTF-8") }

2
spec/services/imports/case_logs_field_import_service_spec.rb

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe Imports::CaseLogsFieldImportService do
subject(:import_service) { described_class.new(storage_service, logger) }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022") }

2
spec/services/imports/case_logs_import_service_spec.rb

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe Imports::CaseLogsImportService do
subject(:case_log_service) { described_class.new(storage_service, logger) }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022") }

2
spec/services/imports/data_protection_confirmation_import_service_spec.rb

@ -5,7 +5,7 @@ RSpec.describe Imports::DataProtectionConfirmationImportService do
let(:old_org_id) { "7c5bd5fb549c09a2c55d7cb90d7ba84927e64618" }
let(:old_id) { old_org_id }
let(:import_file) { File.open("#{fixture_directory}/#{old_id}.xml") }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
context "when importing data protection confirmations" do

2
spec/services/imports/organisation_import_service_spec.rb

@ -1,7 +1,7 @@
require "rails_helper"
RSpec.describe Imports::OrganisationImportService do
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(Rails::Rack::Logger) }
let(:folder_name) { "organisations" }
let(:filenames) { %w[my_folder/my_file1.xml my_folder/my_file2.xml] }

2
spec/services/imports/organisation_rent_period_import_service_spec.rb

@ -5,7 +5,7 @@ RSpec.describe Imports::OrganisationRentPeriodImportService do
let(:old_org_id) { "44026acc7ed5c29516b26f2a5deb639e5e37966d" }
let(:old_id) { "ebd22326d33e389e9f1bfd546979d2c05f9e68d6" }
let(:import_file) { File.open("#{fixture_directory}/#{old_id}.xml") }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
context "when importing organisation rent periods" do

2
spec/services/imports/scheme_import_service_spec.rb

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe Imports::SchemeImportService do
subject(:scheme_service) { described_class.new(storage_service, logger) }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
let(:fixture_directory) { "spec/fixtures/imports/mgmtgroups" }

2
spec/services/imports/scheme_location_import_service_spec.rb

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe Imports::SchemeLocationImportService do
subject(:location_service) { described_class.new(storage_service, logger) }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
let(:fixture_directory) { "spec/fixtures/imports/schemes" }

2
spec/services/imports/user_import_service_spec.rb

@ -5,7 +5,7 @@ RSpec.describe Imports::UserImportService do
let(:old_user_id) { "fc7625a02b24ae16162aa63ae7cb33feeec0c373" }
let(:old_org_id) { "7c5bd5fb549c09a2c55d7cb90d7ba84927e64618" }
let(:user_file) { File.open("#{fixture_directory}/#{old_user_id}.xml") }
let(:storage_service) { instance_double(S3StorageService) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
let(:notify_client) { instance_double(Notifications::Client) }
let(:devise_notify_mailer) { DeviseNotifyMailer.new }

2
spec/services/archive_storage_service_spec.rb → spec/services/storage/archive_service_spec.rb

@ -1,6 +1,6 @@
require "rails_helper"
RSpec.describe ArchiveStorageService do
RSpec.describe Storage::ArchiveService do
subject(:archive_service) { described_class.new(archive_content) }
let(:compressed_folder) { "my_directory" }

28
spec/services/s3_storage_service_spec.rb → spec/services/storage/s3_service_spec.rb

@ -1,6 +1,6 @@
require "rails_helper"
RSpec.describe S3StorageService do
RSpec.describe Storage::S3Service do
let(:instance_name) { "instance_1" }
let(:bucket_name) { "bucket_1" }
let(:vcap_services) do
@ -20,18 +20,24 @@ RSpec.describe S3StorageService do
end
context "when we create a storage service with no PaaS Configuration present" do
subject(:storage_service) { described_class.new(PaasConfigurationService.new, "random_instance") }
subject(:storage_service) { described_class.new(Configuration::PaasConfigurationService.new, "random_instance") }
it "raises an exception" do
expect { storage_service }.to raise_error(RuntimeError, /No PaaS configuration present/)
expect { storage_service }.to raise_error(RuntimeError, "No S3 bucket is present in the PaaS configuration")
end
end
context "when we create a storage service with an unknown instance name" do
subject(:storage_service) { described_class.new(PaasConfigurationService.new, "random_instance") }
context "when we create a storage service and the S3 instance name is not found in the PaaS configuration" do
subject(:storage_service) { described_class.new(Configuration::PaasConfigurationService.new, "random_instance") }
let(:vcap_services) do
<<-JSON
{"aws-s3-bucket": []}
JSON
end
before do
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return("{}")
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services)
end
it "raises an exception" do
@ -40,7 +46,7 @@ RSpec.describe S3StorageService do
end
context "when we create a storage service with a valid instance name" do
subject(:storage_service) { described_class.new(PaasConfigurationService.new, instance_name) }
subject(:storage_service) { described_class.new(Configuration::PaasConfigurationService.new, instance_name) }
before do
allow(ENV).to receive(:[])
@ -48,11 +54,11 @@ RSpec.describe S3StorageService do
end
it "creates a Storage Configuration" do
expect(storage_service.configuration).to be_an(StorageConfiguration)
expect(storage_service.configuration).to be_an(Storage::StorageConfiguration)
end
it "sets the expected parameters in the configuration" do
expected_configuration = StorageConfiguration.new(
expected_configuration = Storage::StorageConfiguration.new(
{
aws_access_key_id: "key_id",
aws_region: "eu-west-2",
@ -65,7 +71,7 @@ RSpec.describe S3StorageService do
end
context "when we create a storage service and write a stubbed object" do
subject(:storage_service) { described_class.new(PaasConfigurationService.new, instance_name) }
subject(:storage_service) { described_class.new(Configuration::PaasConfigurationService.new, instance_name) }
let(:filename) { "my_file" }
let(:content) { "content" }
@ -100,7 +106,7 @@ RSpec.describe S3StorageService do
end
context "when we create a storage service" do
subject(:storage_service) { described_class.new(PaasConfigurationService.new, instance_name) }
subject(:storage_service) { described_class.new(Configuration::PaasConfigurationService.new, instance_name) }
let(:s3_client_stub) { Aws::S3::Client.new(stub_responses: true) }
Loading…
Cancel
Save