Browse Source

Merge branch 'main' into CLDC-638-bulk_upload

pull/84/head
baarkerlounger 4 years ago
parent
commit
e8c868de79
  1. 2
      Gemfile
  2. 3
      Gemfile.lock
  3. 16
      README.md
  4. 112
      config/forms/schema/2021_2022.json
  5. 129
      config/forms/schema/generic.json
  6. 1
      db/migrate/20211112105348_add_incref_field.rb
  7. 4
      db/schema.rb
  8. 44
      lib/tasks/form_definition.rake
  9. 48
      spec/fixtures/forms/test_validator.json
  10. 32
      spec/lib/tasks/form_definition_validator_spec.rb

2
Gemfile

@ -31,6 +31,8 @@ gem "activeadmin"
gem "chartkick" gem "chartkick"
# Spreadsheet parsing # Spreadsheet parsing
gem "roo" gem "roo"
# Json Schema
gem "json-schema"
gem "uk_postcode" gem "uk_postcode"
group :development, :test do group :development, :test do

3
Gemfile.lock

@ -196,6 +196,8 @@ GEM
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
json-schema (2.8.1)
addressable (>= 2.4)
kaminari (1.2.1) kaminari (1.2.1)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.1) kaminari-actionview (= 1.2.1)
@ -402,6 +404,7 @@ DEPENDENCIES
govuk_design_system_formbuilder govuk_design_system_formbuilder
hotwire-rails hotwire-rails
jbuilder (~> 2.7) jbuilder (~> 2.7)
json-schema
listen (~> 3.3) listen (~> 3.3)
overcommit (>= 0.37.0) overcommit (>= 0.37.0)
pg (~> 1.1) pg (~> 1.1)

16
README.md

@ -120,6 +120,7 @@ The JSON should follow the structure:
"[snake_case_question_name_string]": { "[snake_case_question_name_string]": {
"header": String, "header": String,
"hint_text": String, "hint_text": String,
"check_answer_label": String,
"type": "text" / "numeric" / "radio" / "checkbox" / "date", "type": "text" / "numeric" / "radio" / "checkbox" / "date",
"min": Integer, // numeric only "min": Integer, // numeric only
"max": Integer, // numeric only "max": Integer, // numeric only
@ -133,6 +134,10 @@ The JSON should follow the structure:
"[snake_case_question_to_enable_2_name_string]": ["condition-that-enables"] "[snake_case_question_to_enable_2_name_string]": ["condition-that-enables"]
} }
} }
},
"conditional_route_to": {
"[page_name_to_route_to]": {"question_name": "expected_answer"},
"[page_name_to_route_to]": {"question_name": "expected_answer"}
} }
} }
} }
@ -155,6 +160,17 @@ Assumptions made by the format:
- Radio question answer option selected matches one of conditional e.g. ["answer-options-1-string", "answer-option-3-string"] - Radio question answer option selected matches one of conditional e.g. ["answer-options-1-string", "answer-option-3-string"]
- Numeric question value matches condition e.g. [">2"], ["<7"] or ["== 6"] - Numeric question value matches condition e.g. [">2"], ["<7"] or ["== 6"]
## JSON Form Validation against Schema
To validate the form JSON against the schema you can run:
`rake form_definition:validate["config/forms/2021_22.json"]`
This will validate the given form definition against the schema in `config/forms/schema/generic.json`.
You can also run:
`rake form_definition:validate_all`
This will validate all forms in directories = ["config/forms", "spec/fixtures/forms"]
## Useful documentation (external dependencies) ## Useful documentation (external dependencies)
### GOV.UK Design System Form Builder for Rails ### GOV.UK Design System Form Builder for Rails

112
config/forms/schema/2021_2022.json

@ -0,0 +1,112 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://example.com/product.schema.json",
"title": "Form",
"description": "A form",
"type": "object",
"required": ["form_type", "start_year", "end_year", "sections"],
"properties": {
"form_type": {
"description": "",
"type": "string"
},
"start_year": {
"description": "",
"type": "integer"
},
"end_year": {
"description": "",
"type": "integer"
},
"sections": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "",
"type": "object",
"properties": {
"label": {
"description": "",
"type": "string"
},
"subsections": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "",
"type": "object",
"required": ["label"],
"properties": {
"label": {
"description": "",
"type": "string"
},
"pages": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "",
"type": "object",
"properties": {
"header": {
"description": "",
"type": "string"
},
"description": {
"description": "",
"type": "string"
},
"questions": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "",
"type": "object",
"required": ["header", "check_answer_label"],
"properties": {
"check_answer_label": {
"description": "",
"type": "string"
},
"header": {
"description": "",
"type": "string"
},
"type": {
"description": "",
"type": "string"
},
"hint_text": {
"description": "",
"type": "string"
},
"answer_options": {
"description": "",
"type": "object"
},
"conditional_for": {
"description": "",
"type": "object"
}
}
}
}
}
},
"minProperties": 1
}
}
}
},
"minProperties": 1
}
}
}
},
"minProperties": 2
}
},
"minProperties": 1
}
}
}

129
config/forms/schema/generic.json

@ -0,0 +1,129 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://example.com/product.schema.json",
"title": "Form",
"description": "A form",
"type": "object",
"required": ["form_type", "start_year", "end_year", "sections"],
"properties": {
"form_type": {
"description": "",
"type": "string"
},
"start_year": {
"description": "",
"type": "integer"
},
"end_year": {
"description": "",
"type": "integer"
},
"sections": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "Section Name",
"type": "object",
"properties": {
"label": {
"description": "",
"type": "string"
},
"subsections": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "SubSection Name",
"type": "object",
"required": ["label"],
"properties": {
"label": {
"description": "",
"type": "string"
},
"pages": {
"type": "object",
"patternProperties": {
"^(?!(conditional_route_to))[a-z_]+$": {
"description": "Page Name",
"type": "object",
"required": ["header", "questions"],
"properties": {
"header": {
"description": "",
"type": "string"
},
"description": {
"description": "",
"type": "string"
},
"questions": {
"type": "object",
"patternProperties": {
"[a-z_]+": {
"description": "Question Name",
"type": "object",
"required": ["header", "type"],
"properties": {
"header": {
"description": "",
"type": "string"
},
"type": {
"description": "",
"type": "string"
},
"check_answer_label": {
"description": "",
"type": "string",
"optional": "true"
}
},
"additionalProperties": {
"hint_text": {
"optional": "true",
"description": "",
"type": "string"
},
"answer_options": {
"optional": "true",
"description": "",
"type": "object"
},
"check_answer_label": {
"description": "",
"type": "string"
},
"conditional_for": {
"description": "",
"type": "object"
}
},
"minProperties": 1
}
}
}
},
"additionalProperties": {
"conditional_route_to": {
"description": "",
"type": "object"
}
},
"minProperties": 1
}
}
}
},
"minProperties": 1
}
}
}
},
"minProperties": 2
}
},
"minProperties": 1
}
}
}

1
db/migrate/20211112105348_add_incref_field.rb

@ -5,4 +5,3 @@ class AddIncrefField < ActiveRecord::Migration[6.1]
end end
end end
end end

4
db/schema.rb

@ -122,8 +122,6 @@ ActiveRecord::Schema.define(version: 2021_11_12_105348) do
t.integer "rp_dontknow" t.integer "rp_dontknow"
t.datetime "discarded_at" t.datetime "discarded_at"
t.string "tenancyother" t.string "tenancyother"
t.integer "override_net_income_validation"
t.string "net_income_known"
t.string "gdpr_acceptance" t.string "gdpr_acceptance"
t.string "gdpr_declined" t.string "gdpr_declined"
t.string "property_owner_organisation" t.string "property_owner_organisation"
@ -135,6 +133,8 @@ ActiveRecord::Schema.define(version: 2021_11_12_105348) do
t.string "needs_type" t.string "needs_type"
t.string "sale_completion_date" t.string "sale_completion_date"
t.string "purchaser_code" t.string "purchaser_code"
t.integer "override_net_income_validation"
t.string "net_income_known"
t.integer "reason" t.integer "reason"
t.string "propcode" t.string "propcode"
t.integer "majorrepairs" t.integer "majorrepairs"

44
lib/tasks/form_definition.rake

@ -0,0 +1,44 @@
require "json"
require "json-schema"
def get_all_form_paths(directories)
form_paths = []
directories.each do |directory|
Dir.glob("#{directory}/*.json").each do |form_path|
form_paths.push(form_path)
end
end
form_paths
end
namespace :form_definition do
desc "Validate JSON against Generic Form Schema"
task validate_all: :environment do
puts Rails.root.to_s
directories = ["config/forms", "spec/fixtures/forms"]
paths = get_all_form_paths(directories) + ["config/forms/schema/generic.json"]
paths.each do |path|
Rake::Task["form_definition:validate"].reenable
Rake::Task["form_definition:validate"].invoke(path)
end
end
task :validate, %i[path] => :environment do |_task, args|
path = Rails.root.join(args.path)
file = File.open(path)
form_definition = JSON.parse(file.read)
schema = JSON::Validator.validator_for_name("draft4").metaschema
puts path
puts JSON::Validator.fully_validate(schema, form_definition, strict: true)
begin
JSON::Validator.validate!(schema, form_definition)
rescue JSON::Schema::ValidationError => e
e.message
end
end
end

48
spec/fixtures/forms/test_validator.json vendored

@ -0,0 +1,48 @@
{
"form_type": "lettings",
"start_year": 2021,
"end_year": 2022,
"sections": {
"household": {
"label": "About the household",
"subsections": {
"household_characteristics": {
"label": "Household characteristics",
"ShouldThrowError": "Shouldn't be here but what you gonna do?",
"pages": {
"tenant_code": {
"header": "",
"description": "",
"ShouldThrowError": "Shouldn't be here but what you gonna do?",
"questions": {
"tenant_code": {
"check_answer_label": "Tenant code",
"header": "What is the tenant code?",
"description": "",
"type": "text"
}
},
"conditional_route_to": {"test": "Yes"}
},
"conditional_route_to": {"test": "Yes"},
"person_1_age": {
"header": "",
"description": "",
"questions": {
"person_1_age": {
"check_answer_label": "Tenant's age",
"header": "What is the tenant's age?",
"hint_text": "",
"type": "numeric",
"min": 0,
"max": 120,
"step": 1
}
}
}
}
}
}
}
}
}

32
spec/lib/tasks/form_definition_validator_spec.rb

@ -0,0 +1,32 @@
require "rails_helper"
require "rake"
describe "rake form_definition:validate_all", type: :task do
subject(:task) { Rake::Task["form_definition:validate_all"] }
before do
Rake.application.rake_require("tasks/form_definition")
Rake::Task.define_task(:environment)
task.reenable
end
it "runs the validate task for each form definition in the project" do
expect(Rake::Task["form_definition:validate"]).to receive(:invoke).exactly(5).times
task.invoke
end
end
describe "rake form_definition:validate", type: :task do
subject(:task) { Rake::Task["form_definition:validate"] }
before do
Rake.application.rake_require("tasks/form_definition")
Rake::Task.define_task(:environment)
task.reenable
end
it "runs the validate task for the given form definition" do
expect(JSON::Validator).to receive(:validate!).at_least(1).time
task.invoke("config/forms/2021_2022.json")
end
end
Loading…
Cancel
Save