diff --git a/.env b/.env new file mode 100644 index 0000000..af23d07 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +DATABASE_URL=postgres://postgres:postgres@localhost/postgres diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 18ed769..ad40002 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,8 +1,7 @@ name: Deploy to GOV.UK PaaS on: - push: - branches: [main] + workflow_dispatch: env: REGISTRY: ghcr.io diff --git a/.gitignore b/.gitignore index 01d802c..33534c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ forms/ +*target/ diff --git a/Gemfile b/Gemfile index e5666f8..c2c8f27 100644 --- a/Gemfile +++ b/Gemfile @@ -7,3 +7,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } gem "sinatra" gem "pry" gem "thin" +gem "pg" +gem "sequel" +gem "dotenv" +gem "jwt" diff --git a/Gemfile.lock b/Gemfile.lock index cb931c0..0377d70 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,10 +3,13 @@ GEM specs: coderay (1.1.3) daemons (1.4.1) + dotenv (2.7.6) eventmachine (1.2.7) + jwt (2.3.0) method_source (1.0.0) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) + pg (1.2.3) pry (0.14.1) coderay (~> 1.1) method_source (~> 1.0) @@ -14,6 +17,7 @@ GEM rack-protection (2.1.0) rack ruby2_keywords (0.0.5) + sequel (5.52.0) sinatra (2.1.0) mustermann (~> 1.0) rack (~> 2.2) @@ -29,7 +33,11 @@ PLATFORMS x86_64-linux DEPENDENCIES + dotenv + jwt + pg pry + sequel sinatra thin diff --git a/README.md b/README.md index ed74861..fe220ae 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # GOV.UK Forms API Prototype A prototype for a forms API for the GOV.UK Forms team built with Ruby and Sinatra. + +## Running the database with docker + +`docker run --name db -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres:13` diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..cbaf76f --- /dev/null +++ b/config.ru @@ -0,0 +1,5 @@ +RACK_ENV = ENV['RACK_ENV'] ||= 'development' unless defined?(RACK_ENV) +require_relative 'loader' +require_relative './server' + +run Server diff --git a/db/database.rb b/db/database.rb new file mode 100644 index 0000000..60c1b91 --- /dev/null +++ b/db/database.rb @@ -0,0 +1,40 @@ +require "sequel" + +class Migrator + def initialize + Sequel.extension :migration + end + + def destroy(database) + Sequel::Migrator.run(database, "#{__dir__}/migrations", target: 0) + end + + def migrate(database) + Sequel::Migrator.run(database, "#{__dir__}/migrations") + end + + def migrate_to(database, version) + Sequel::Migrator.run(database, "#{__dir__}/migrations", target: version) + end +end + +class Database + def initialize + @migrator = Migrator.new + end + + def connect + database = Sequel.connect(ENV['DATABASE_URL']) + load_extensions_for(database) + + @migrator.migrate(database) + database + end + + private + + def load_extensions_for(database) + database.extension :pg_json + database.extension :pg_array + end +end diff --git a/db/migrations/1_add_forms_table.rb b/db/migrations/1_add_forms_table.rb new file mode 100644 index 0000000..9c3b649 --- /dev/null +++ b/db/migrations/1_add_forms_table.rb @@ -0,0 +1,11 @@ +Sequel.migration do + change do + create_table :forms do + primary_key :id, type: :Bignum + String :username + String :key + String :display_name + column :form, 'json' + end + end +end diff --git a/example_forms/get-condition-evaluation-context b/example_forms/get-condition-evaluation-context new file mode 100644 index 0000000..015d4bd --- /dev/null +++ b/example_forms/get-condition-evaluation-context @@ -0,0 +1,678 @@ +{ + "startPage": "/uk-passport", + "pages": [ + { + "path": "/uk-passport", + "components": [ + { + "type": "YesNoField", + "name": "ukPassport", + "title": "Do you have a UK passport?", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "section": "checkBeforeYouStart", + "next": [ + { + "path": "/how-many-people" + }, + { + "path": "/anothertest", + "condition": "WLkGmF" + }, + { + "path": "/testconditions", + "condition": "doesntHaveUKPassport" + } + ], + "title": "Do you have a UK passport?" + }, + { + "path": "/how-many-people", + "section": "applicantDetails", + "components": [ + { + "options": { + "classes": "govuk-input--width-10", + "required": true + }, + "type": "SelectField", + "name": "numberOfApplicants", + "title": "How many applicants are there?", + "list": "numberOfApplicants", + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-one-name" + } + ], + "title": "How many applicants are there?" + }, + { + "path": "/applicant-one-name", + "title": "Applicant 1", + "section": "applicantOneDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-one-address" + } + ] + }, + { + "path": "/applicant-one-address", + "section": "applicantOneDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-two", + "condition": "moreThanOneApplicant" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-two", + "title": "Applicant 2", + "section": "applicantTwoDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-two-address" + } + ] + }, + { + "path": "/applicant-two-address", + "section": "applicantTwoDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-three", + "condition": "moreThanTwoApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-three", + "title": "Applicant 3", + "section": "applicantThreeDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-three-address" + } + ] + }, + { + "path": "/applicant-three-address", + "section": "applicantThreeDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-four", + "condition": "moreThanThreeApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-four", + "title": "Applicant 4", + "section": "applicantFourDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-four-address" + } + ] + }, + { + "path": "/applicant-four-address", + "section": "applicantFourDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/contact-details", + "section": "applicantDetails", + "components": [ + { + "type": "TelephoneNumberField", + "name": "phoneNumber", + "title": "Phone number", + "hint": "If you haven't got a UK phone number, include country code", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "EmailAddressField", + "name": "emailAddress", + "title": "Your email address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/testconditions" + } + ], + "title": "Applicant contact details" + }, + { + "path": "/summary", + "controller": "./pages/summary.js", + "title": "Summary", + "components": [ + + ], + "next": [ + + ] + }, + { + "path": "/testconditions", + "title": "TestConditions", + "components": [ + { + "name": "pmmRYP", + "options": { + "condition": "bDDfgf" + }, + "type": "Para", + "content": "There Is Someone Called Applicant", + "schema": { + + } + } + ], + "next": [ + { + "path": "/summary" + } + ] + }, + { + "path": "/anothertest", + "title": "AnotherTest", + "components": [ + { + "name": "FnMsqX", + "options": { + + }, + "type": "Para", + "content": "Another Page" + } + ], + "next": [ + { + "path": "/summary" + } + ] + } + ], + "lists": [ + { + "name": "numberOfApplicants", + "title": "Number of people", + "type": "number", + "items": [ + { + "text": "1", + "value": 1, + "description": "", + "condition": "" + }, + { + "text": "2", + "value": 2, + "description": "", + "condition": "" + }, + { + "text": "3", + "value": 3, + "description": "", + "condition": "" + }, + { + "text": "4", + "value": 4, + "description": "", + "condition": "" + } + ] + } + ], + "sections": [ + { + "name": "checkBeforeYouStart", + "title": "Check before you start" + }, + { + "name": "applicantDetails", + "title": "Applicant details" + }, + { + "name": "applicantOneDetails", + "title": "Applicant 1" + }, + { + "name": "applicantTwoDetails", + "title": "Applicant 2" + }, + { + "name": "applicantThreeDetails", + "title": "Applicant 3" + }, + { + "name": "applicantFourDetails", + "title": "Applicant 4" + } + ], + "phaseBanner": { + + }, + "fees": [ + + ], + "outputs": [ + { + "name": "Ric43H5Ctwl4NBDC9x1_4", + "title": "email", + "type": "email", + "outputConfiguration": { + "emailAddress": "jennifermyanh.duong@digital.homeoffice.gov.uk" + } + } + ], + "declaration": "
All the answers you have provided are true to the best of your knowledge.
", + "version": 2, + "conditions": [ + { + "name": "hasUKPassport", + "displayName": "hasUKPassport", + "value": "checkBeforeYouStart.ukPassport==true" + }, + { + "name": "moreThanOneApplicant", + "displayName": "moreThanOneApplicant", + "value": "applicantDetails.numberOfApplicants > 1" + }, + { + "name": "moreThanTwoApplicants", + "displayName": "moreThanTwoApplicants", + "value": "applicantDetails.numberOfApplicants > 2" + }, + { + "name": "moreThanThreeApplicants", + "displayName": "moreThanThreeApplicants", + "value": "applicantDetails.numberOfApplicants > 3" + }, + { + "displayName": "Another", + "name": "nAQyYp", + "value": { + "name": "Another", + "conditions": [ + { + "conditionName": "doesntHaveUKPassport", + "conditionDisplayName": "doesntHaveUKPassport" + } + ] + } + }, + { + "displayName": "Another2", + "name": "QFdzTQ", + "value": { + "name": "Another2", + "conditions": [ + { + "field": { + "name": "checkBeforeYouStart.ukPassport", + "type": "YesNoField", + "display": "Do you have a UK passport?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "true", + "display": "true" + } + } + ] + } + }, + { + "displayName": "Another3", + "name": "WLkGmF", + "value": { + "name": "Another3", + "conditions": [ + { + "field": { + "name": "applicantOneDetails.firstName", + "type": "TextField", + "display": "First name" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Applicant", + "display": "Applicant" + } + }, + { + "coordinator": "and", + "field": { + "name": "checkBeforeYouStart.ukPassport", + "type": "YesNoField", + "display": "Do you have a UK passport?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "false", + "display": "false" + } + } + ] + } + }, + { + "name": "bDDfgf", + "displayName": "testCondition", + "value": { + "name": "testCondition", + "conditions": [ + { + "field": { + "name": "applicantOneDetails.firstName", + "type": "TextField", + "display": "First name" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Applicant", + "display": "Applicant" + } + } + ] + } + }, + { + "name": "doesntHaveUKPassport", + "displayName": "doesntHaveUKPassport", + "value": "checkBeforeYouStart.ukPassport==false" + } + ], + "skipSummary": false +} diff --git a/example_forms/report-a-terrorist b/example_forms/report-a-terrorist new file mode 100644 index 0000000..d2eabf6 --- /dev/null +++ b/example_forms/report-a-terrorist @@ -0,0 +1,281 @@ +{ + "startPage": "/do-you-have-a-link-to-the-evidence", + "pages": [ + { + "title": "Do you have a link to the evidence?", + "path": "/do-you-have-a-link-to-the-evidence", + "components": [ + { + "name": "UjidZI", + "options": {}, + "type": "Para", + "content": "It’s helpful if you can send us links to the relevant pages, or posts if it was posted on social media.", + "schema": {} + }, + { + "name": "rfUYC", + "options": {}, + "type": "Details", + "title": "Help me find the link", + "content": "If you’re on a website, the link appears in the bar at the top of the page. An example of a link is, www.gov.uk/page/1234/content#.", + "schema": {} + }, + { + "type": "RadiosField", + "title": "Do you have a link to the material?", + "options": { + "hideTitle": true + }, + "name": "doyouhavealink", + "schema": {}, + "list": "HTbt4V" + } + ], + "next": [ + { + "path": "/do-you-have-any-evidence" + }, + { + "path": "/yes-i-have-a-link-to-the-material", + "condition": "b-NGgWvGISkJJLuzsJIjv" + } + ], + "section": "PMXq1s" + }, + { + "path": "/do-you-have-any-evidence", + "title": "Do you have any evidence?", + "components": [ + { + "name": "OQrrkG", + "options": {}, + "type": "Para", + "content": "This could be an image or video, for example. Evidence is helpful should the material be deleted before we can find it.It’s safe to save evidence to your device for the purpose of reporting it to us. We recommend deleting it afterwards.", + "schema": {} + }, + { + "name": "3jdOpV", + "options": {}, + "type": "Details", + "title": "Help me take a screenshot", + "content": "Try this:Press the Shift key (⇧), command (or Cmd), and 3The screenshot will be saved to your DesktopYou can now upload it to the formTry this:Press the Ctrl key and the switch window keyThe screenshot will be saved to your DownloadsYou can now upload it to the formIf that doesn’t work, try pressing Ctrl and F5.When viewing the material:Press the Prt Scr key (or similar) to take a copy of your screenPaste the image into Microsoft Paint or a similar applicationSave the file to your computerUpload the file to the formIf that doesn’t work, you may need to search for how to take screenshots on your particular computer model.", + "schema": {} + }, + { + "name": "LU6RMD", + "options": {}, + "type": "RadiosField", + "title": "Do you have any evidence?", + "schema": {}, + "list": "mdmRq9" + } + ], + "next": [ + { + "path": "/is-there-anything-else-you-can-tell-us" + }, + { + "path": "/yes-i-have-evidence", + "condition": "On5IOaSRDSyLs1G7-Dmdy" + } + ], + "section": "PMXq1s" + }, + { + "title": "summary", + "path": "/summary", + "controller": "./pages/summary.js", + "components": [] + }, + { + "path": "/is-there-anything-else-you-can-tell-us", + "title": "Is there anything else you can tell us?", + "components": [ + { + "name": "HETM3o", + "options": {}, + "type": "Para", + "content": "Details may include:who shared the materialwhen it was shareda description, if you haven’t provided a link or evidence", + "schema": {} + }, + { + "name": "evZ-IJ", + "options": { + "required": false + }, + "type": "MultilineTextField", + "title": "Additional Info", + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ], + "section": "PMXq1s" + }, + { + "path": "/yes-i-have-a-link-to-the-material", + "title": "Yes I have a link to the material", + "components": [ + { + "type": "MultilineTextField", + "title": "Link to the material", + "hint": "Please put in the link to the material here", + "name": "blarGGH", + "options": {}, + "schema": {} + } + ], + "next": [ + { + "path": "/do-you-have-any-evidence" + } + ], + "section": "PMXq1s" + }, + { + "path": "/yes-i-have-evidence", + "title": "Yes I have evidence", + "components": [ + { + "name": "koE_ae", + "options": { + "required": false + }, + "type": "FileUploadField", + "title": "Evidence File Upload", + "hint": "Please upload your evidence here", + "schema": {} + } + ], + "next": [ + { + "path": "/is-there-anything-else-you-can-tell-us" + } + ], + "section": "PMXq1s" + } + ], + "lists": [ + { + "title": "linktomateriallist", + "name": "HTbt4V", + "type": "string", + "items": [ + { + "text": "Yes, I do have a link", + "value": "yes" + }, + { + "text": "No, I don't have a link", + "value": "no" + } + ] + }, + { + "title": "evidencelist", + "name": "mdmRq9", + "type": "string", + "items": [ + { + "text": "Yes, I have evidence", + "value": "yes" + }, + { + "text": "No, I don't have evidence", + "value": "no" + } + ] + } + ], + "sections": [ + { + "name": "PMXq1s", + "title": "Evidence" + } + ], + "phaseBanner": {}, + "metadata": {}, + "fees": [], + "outputs": [ + { + "name": "q7mMOb6Eu6EauibjcTFT3", + "title": "powerapps", + "type": "webhook", + "outputConfiguration": { + "url": "https://prod-182.westeurope.logic.azure.com:443/workflows/cfa66b774dad40459bf36e334d860445/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=4nNQTOYk5DnEByQSKMb5jzu_cXJ0NKJuH4KZGBiqvMk" + } + } + ], + "version": 2, + "conditions": [ + { + "name": "b-NGgWvGISkJJLuzsJIjv", + "displayName": "hasLink", + "value": { + "name": "hasLink", + "conditions": [ + { + "field": { + "name": "PMXq1s.doyouhavealink", + "type": "RadiosField", + "display": "Do you have a link to the material? in PMXq1s" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "yes", + "display": "Yes, I do have a link" + } + } + ] + } + }, + { + "name": "xY51EDbc4lPr6kHZl1umG", + "displayName": "noEvidence", + "value": { + "name": "noEvidence", + "conditions": [ + { + "field": { + "name": "PMXq1s.LU6RMD", + "type": "RadiosField", + "display": "Do you have any evidence? in PMXq1s" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "no", + "display": "No, I don't have evidence" + } + } + ] + } + }, + { + "name": "On5IOaSRDSyLs1G7-Dmdy", + "displayName": "hasEvidence", + "value": { + "name": "hasEvidence", + "conditions": [ + { + "field": { + "name": "PMXq1s.LU6RMD", + "type": "RadiosField", + "display": "Do you have any evidence? in PMXq1s" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "yes", + "display": "Yes, I have evidence" + } + } + ] + } + } + ] +} diff --git a/example_forms/runner-components-test b/example_forms/runner-components-test new file mode 100644 index 0000000..3831649 --- /dev/null +++ b/example_forms/runner-components-test @@ -0,0 +1,379 @@ +{ + "startPage": "/do-you-own-a-vehicle", + "pages": [ + { + "title": "Do you own a vehicle?", + "path": "/do-you-own-a-vehicle", + "components": [ + { + "name": "qqbRw1", + "options": {}, + "type": "YesNoField", + "title": "Do you own a vehicle?", + "values": { + "type": "listRef" + }, + "schema": {} + }, + { + "name": "LdOljB", + "options": {}, + "type": "InsetText", + "content": "It does not matter what you pick as it will redirect you to the same page", + "schema": {} + } + ], + "next": [ + { + "path": "/what-address-is-the-vehicle-registered-to" + } + ] + }, + { + "path": "/what-address-is-the-vehicle-registered-to", + "title": "What address is the vehicle registered to?", + "components": [ + { + "name": "sFR4aX", + "options": {}, + "type": "UkAddressField", + "title": "What address is the vehicle registered to?", + "schema": {} + }, + { + "name": "tVlnZa", + "options": {}, + "type": "DateField", + "title": "What date was the vehicle registered at this address?", + "schema": {} + }, + { + "name": "Z0Guyn", + "options": {}, + "type": "CheckboxesField", + "title": "Which Clean Air Zones are you claiming an exemption for?", + "list": "O2uEB1", + "hint": "Please check all that apply, however you are restricted to a maximum of two choices.", + "schema": {} + }, + { + "name": "M8gMK7", + "options": { + "required": false + }, + "type": "FileUploadField", + "title": "Proof of address", + "hint": "This can be a drivers licence or utility bill dated with the last month", + "schema": {} + } + ], + "next": [ + { + "path": "/details-about-your-vehicle" + } + ] + }, + { + "path": "/clean-air-zone-caz-exemption", + "title": "Clean Air Zone (CAZ) Exemption", + "components": [ + { + "name": "MOB13t", + "options": {}, + "type": "Para", + "content": "How to check if you're exempt from paying a charge and how to create a business account, and what support or exemptions are available. ", + "schema": {} + } + ], + "next": [ + { + "path": "/do-you-own-a-vehicle" + } + ], + "controller": "./pages/start.js" + }, + { + "path": "/details-about-your-vehicle", + "title": "Details about your vehicle", + "components": [ + { + "name": "0ZVmN_", + "options": {}, + "type": "AutocompleteField", + "title": "What is the make of you vehicle?", + "list": "-HMHHj", + "schema": {} + }, + { + "name": "gHSgo2", + "options": {}, + "type": "TextField", + "title": "Vehicle Model", + "hint": "For example A1, 740, Elantra", + "schema": {} + }, + { + "name": "4LZ9to", + "options": {}, + "type": "DatePartsField", + "title": "Date you purchased the vehicle?", + "schema": {} + }, + { + "type": "RadiosField", + "title": "What fuel type does your vehicle use?", + "list": "sm_ssM", + "name": "fsfsdfsdf", + "nameHasError": false, + "options": {}, + "schema": {} + }, + { + "name": "chYCuk", + "options": {}, + "type": "MultilineTextField", + "title": "Has the vehicle been modified in any way?", + "hint": "Failure to declare modifications will result in severe penalties if not disclosed at this point.", + "schema": {} + } + ], + "next": [ + { + "path": "/driver-details" + } + ] + }, + { + "path": "/driver-details", + "title": "Driver details", + "components": [ + { + "name": "wJzPKE", + "options": {}, + "type": "NumberField", + "title": "How many people in your household drive this vehicle?", + "schema": {} + }, + { + "name": "PNIThU", + "options": {}, + "type": "TextField", + "title": "Full name of the main driver", + "hint": "Please exclude your title", + "schema": {} + }, + { + "name": "0zL5bB", + "options": {}, + "type": "TelephoneNumberField", + "title": "Contact number", + "hint": "Landline or mobile", + "schema": {} + } + ], + "next": [ + { + "path": "/final-steps" + } + ] + }, + { + "path": "/final-steps", + "title": "final steps", + "components": [ + { + "name": "fkd8av", + "options": {}, + "type": "List", + "title": "Declaration", + "list": "mJHWaC", + "schema": {} + }, + { + "name": "L_2AYe", + "options": {}, + "type": "EmailAddressField", + "title": "Your email address", + "hint": "We will send confirmation of your application to the provided email address", + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ] + }, + { + "path": "/summary", + "title": "Summary", + "components": [], + "next": [], + "controller": "./pages/summary.js" + } + ], + "lists": [ + { + "title": "Vehicle Type", + "name": "ckrDmV", + "type": "string", + "items": [ + { + "text": "Car", + "value": 1 + }, + { + "text": "4 x 4/SUV", + "value": 2 + }, + { + "text": "Van", + "value": 3 + }, + { + "text": "Motorbike/Moped", + "value": 4 + } + ] + }, + { + "title": "Vehicle Make", + "name": "-HMHHj", + "type": "string", + "items": [ + { + "text": "Alfa Romeo", + "value": 1 + }, + { + "text": "BMW", + "value": 2 + }, + { + "text": "Ford", + "value": 3 + }, + { + "text": "Citroen", + "value": 4 + }, + { + "text": "Nissan", + "value": 5 + }, + { + "text": "Honda", + "value": 6 + }, + { + "text": "Mercedes", + "value": 8 + }, + { + "text": "Audi", + "value": 9 + }, + { + "text": "Toyota", + "value": 10 + }, + { + "text": "Hyundai", + "value": 11 + }, + { + "text": "Kia", + "value": 12 + } + ] + }, + { + "title": "Fuel types", + "name": "sm_ssM", + "type": "string", + "items": [ + { + "text": "Diesel", + "value": 1 + }, + { + "text": "Electric", + "value": 2 + }, + { + "text": "Hydrogen", + "value": 3 + }, + { + "text": "Petrol", + "value": 4 + }, + { + "text": "Hybrid", + "value": 5 + } + ] + }, + { + "title": "CAZ Location", + "name": "O2uEB1", + "type": "string", + "items": [ + { + "text": "Bath", + "value": 1 + }, + { + "text": "Bristol", + "value": 2 + }, + { + "text": "Birmingham", + "value": 3 + }, + { + "text": "Cardiff", + "value": 4 + }, + { + "text": "Liverpool", + "value": 6 + }, + { + "text": "Leeds", + "value": 7 + }, + { + "text": "Manchester", + "value": 8 + } + ] + }, + { + "title": "Declaration", + "name": "mJHWaC", + "type": "string", + "items": [ + { + "text": "You are not a Robot", + "value": 1 + }, + { + "text": "You have not previously claimed an exemption", + "value": 2 + }, + { + "text": "You have not omitted or purposely witheld information that might be detrimental to you claim", + "value": 3 + } + ] + } + ], + "sections": [], + "phaseBanner": {}, + "metadata": {}, + "fees": [], + "outputs": [], + "version": 2, + "conditions": [] +} \ No newline at end of file diff --git a/example_forms/test b/example_forms/test new file mode 100644 index 0000000..59b6701 --- /dev/null +++ b/example_forms/test @@ -0,0 +1,509 @@ +{ + "startPage": "/start", + "pages": [ + { + "title": "Start", + "path": "/start", + "components": [], + "next": [ + { + "path": "/uk-passport" + } + ], + "controller": "./pages/start.js" + }, + { + "path": "/uk-passport", + "components": [ + { + "type": "YesNoField", + "name": "ukPassport", + "title": "Do you have a UK passport?", + "options": { + "required": true + }, + "schema": {} + } + ], + "section": "checkBeforeYouStart", + "next": [ + { + "path": "/how-many-people" + }, + { + "path": "/no-uk-passport", + "condition": "doesntHaveUKPassport" + } + ], + "title": "Do you have a UK passport?" + }, + { + "path": "/no-uk-passport", + "title": "You're not eligible for this service", + "components": [ + { + "type": "Para", + "content": "If you still think you're eligible please contact the Foreign and Commonwealth Office.", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [] + }, + { + "path": "/how-many-people", + "section": "applicantDetails", + "components": [ + { + "options": { + "classes": "govuk-input--width-10", + "required": true + }, + "type": "SelectField", + "name": "numberOfApplicants", + "title": "How many applicants are there?", + "list": "numberOfApplicants" + } + ], + "next": [ + { + "path": "/applicant-one" + } + ], + "title": "How many applicants are there?" + }, + { + "path": "/applicant-one", + "title": "Applicant 1", + "section": "applicantOneDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-one-address" + } + ] + }, + { + "path": "/applicant-one-address", + "section": "applicantOneDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-two", + "condition": "moreThanOneApplicant" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-two", + "title": "Applicant 2", + "section": "applicantTwoDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-two-address" + } + ] + }, + { + "path": "/applicant-two-address", + "section": "applicantTwoDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-three", + "condition": "moreThanTwoApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-three", + "title": "Applicant 3", + "section": "applicantThreeDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-three-address" + } + ] + }, + { + "path": "/applicant-three-address", + "section": "applicantThreeDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-four", + "condition": "moreThanThreeApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-four", + "title": "Applicant 4", + "section": "applicantFourDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-four-address" + } + ] + }, + { + "path": "/applicant-four-address", + "section": "applicantFourDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/contact-details", + "section": "applicantDetails", + "components": [ + { + "type": "TelephoneNumberField", + "name": "phoneNumber", + "title": "Phone number", + "hint": "If you haven't got a UK phone number, include country code", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "EmailAddressField", + "name": "emailAddress", + "title": "Your email address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ], + "title": "Applicant contact details" + }, + { + "path": "/summary", + "controller": "./pages/summary.js", + "title": "Summary", + "components": [], + "next": [] + } + ], + "lists": [ + { + "name": "numberOfApplicants", + "title": "Number of people", + "type": "number", + "items": [ + { + "text": "1", + "value": 1, + "description": "", + "condition": "" + }, + { + "text": "2", + "value": 2, + "description": "", + "condition": "" + }, + { + "text": "3", + "value": 3, + "description": "", + "condition": "" + }, + { + "text": "4", + "value": 4, + "description": "", + "condition": "" + } + ] + } + ], + "sections": [ + { + "name": "checkBeforeYouStart", + "title": "Check before you start" + }, + { + "name": "applicantDetails", + "title": "Applicant details" + }, + { + "name": "applicantOneDetails", + "title": "Applicant 1" + }, + { + "name": "applicantTwoDetails", + "title": "Applicant 2" + }, + { + "name": "applicantThreeDetails", + "title": "Applicant 3" + }, + { + "name": "applicantFourDetails", + "title": "Applicant 4" + } + ], + "phaseBanner": {}, + "fees": [], + "payApiKey": "", + "outputs": [ + { + "name": "Ric43H5Ctwl4NBDC9x1_4", + "title": "email", + "type": "email", + "outputConfiguration": { + "emailAddress": "jennifermyanh.duong@digital.homeoffice.gov.uk" + } + } + ], + "declaration": "All the answers you have provided are true to the best of your knowledge.
", + "version": 2, + "conditions": [ + { + "name": "hasUKPassport", + "displayName": "hasUKPassport", + "value": "checkBeforeYouStart.ukPassport==true" + }, + { + "name": "doesntHaveUKPassport", + "displayName": "doesntHaveUKPassport", + "value": "checkBeforeYouStart.ukPassport==false" + }, + { + "name": "moreThanOneApplicant", + "displayName": "moreThanOneApplicant", + "value": "applicantDetails.numberOfApplicants > 1" + }, + { + "name": "moreThanTwoApplicants", + "displayName": "moreThanTwoApplicants", + "value": "applicantDetails.numberOfApplicants > 2" + }, + { + "name": "moreThanThreeApplicants", + "displayName": "moreThanThreeApplicants", + "value": "applicantDetails.numberOfApplicants > 3" + } + ] +} diff --git a/loader.rb b/loader.rb new file mode 100644 index 0000000..0297418 --- /dev/null +++ b/loader.rb @@ -0,0 +1,2 @@ +require 'dotenv/load' + diff --git a/manifest.yml b/manifest.yml index 7903776..603b827 100644 --- a/manifest.yml +++ b/manifest.yml @@ -2,4 +2,6 @@ applications: - name: cifu-xgov-persistence-service memory: 256M - command: bundle exec rackup + command: bundle exec rackup -p $PORT + services: + - cifu-xgov-form-api-db diff --git a/rust-api/.dockerignore b/rust-api/.dockerignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/rust-api/.dockerignore @@ -0,0 +1 @@ +target/ diff --git a/rust-api/.env b/rust-api/.env new file mode 100644 index 0000000..7ed9819 --- /dev/null +++ b/rust-api/.env @@ -0,0 +1,2 @@ +DATABASE_URL=postgres://postgres:password@localhost/postgres +RUST_LOG=debug diff --git a/rust-api/Cargo.lock b/rust-api/Cargo.lock new file mode 100644 index 0000000..6bd7432 --- /dev/null +++ b/rust-api/Cargo.lock @@ -0,0 +1,2252 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" + +[[package]] +name = "async-trait" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.44", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "color-eyre" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6ec7641ff3474b7593009c809db602c414cd97c7d47a78ed004162b74ff96c" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" +dependencies = [ + "aes-gcm", + "base64 0.13.0", + "hkdf", + "hmac 0.12.1", + "percent-encoding", + "rand", + "sha2 0.10.2", + "subtle", + "time 0.3.7", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crossbeam-channel" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.1", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "eyre" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc225d8f637923fe585089fcf03e705c222131232d2c1fb622e84ecf725d0eb8" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-intrusive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "h2" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +dependencies = [ + "bytes 1.1.0", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "headers" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84c647447a07ca16f5fbd05b633e535cc41a08d2d74ab1e08648df53be9cb89" +dependencies = [ + "base64 0.13.0", + "bitflags", + "bytes 1.1.0", + "headers-core", + "http", + "httpdate", + "mime", + "sha-1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158bc31e00a68e380286904cc598715f861f2b0ccf7aa6fe20c6d0c49ca5d0f6" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes 1.1.0", + "fnv", + "itoa 1.0.1", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes 1.1.0", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +dependencies = [ + "bytes 1.1.0", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 0.4.8", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jwt" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98328bb4f360e6b2ceb1f95645602c7014000ef0c3809963df8ad3a3a09f8d99" +dependencies = [ + "base64 0.13.0", + "crypto-mac", + "digest 0.9.0", + "hmac 0.11.0", + "serde", + "serde_json", + "sha2 0.9.9", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" + +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "md-5" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "multer" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f8f35e687561d5c1667590911e6698a8cb714a134a7505718a182e7bc9d3836" +dependencies = [ + "bytes 1.1.0", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin", + "tokio", + "version_check", +] + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "owo-colors" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20448fd678ec04e6ea15bbe0476874af65e98a01515d667aa49f1434dc44ebf4" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "poem" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3644551d7c91b980ed277647f16e7afadf3f9f0e24ef3b9f9ecc8d669246544a" +dependencies = [ + "async-trait", + "bytes 1.1.0", + "chrono", + "cookie", + "futures-util", + "headers", + "http", + "hyper", + "mime", + "multer", + "parking_lot", + "percent-encoding", + "pin-project-lite", + "poem-derive", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "tempfile", + "thiserror", + "time 0.3.7", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", +] + +[[package]] +name = "poem-derive" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c90bc5b98d8ed3822067d4664a2e9ba7ea3a7f2521bb55d7838009f1360fde62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "poem-openapi" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "547734c796c971f12e901b444eafe22bd8c8f48292ca88e9b0fd96cef386793e" +dependencies = [ + "base64 0.13.0", + "bytes 1.1.0", + "derive_more", + "futures-util", + "mime", + "num-traits", + "poem", + "poem-openapi-derive", + "regex", + "serde", + "serde_json", + "thiserror", + "tokio", + "typed-headers", + "url", +] + +[[package]] +name = "poem-openapi-derive" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650fbd595b55886d9d203ac6530c079251dd4069b26fc3185d3e400a379720ff" +dependencies = [ + "Inflector", + "darling", + "http", + "indexmap", + "mime", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", + "thiserror", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rust-api" +version = "0.1.0" +dependencies = [ + "anyhow", + "color-eyre", + "dotenv", + "hmac 0.11.0", + "jwt", + "poem", + "poem-openapi", + "rand", + "serde", + "serde_json", + "sha2 0.9.9", + "sqlx", + "tokio", + "tracing", + "tracing-subscriber 0.2.25", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "indexmap", + "itoa 1.0.1", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.1", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" + +[[package]] +name = "sqlformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016" +dependencies = [ + "ahash", + "atoi", + "base64 0.13.0", + "bitflags", + "byteorder", + "bytes 1.1.0", + "crc", + "crossbeam-channel", + "crossbeam-queue", + "crossbeam-utils", + "dirs", + "either", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-util", + "hashlink", + "hex", + "hmac 0.11.0", + "indexmap", + "itoa 1.0.1", + "libc", + "log", + "md-5", + "memchr", + "once_cell", + "parking_lot", + "percent-encoding", + "rand", + "serde", + "serde_json", + "sha-1", + "sha2 0.9.9", + "smallvec", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "tokio-stream", + "url", + "whoami", +] + +[[package]] +name = "sqlx-macros" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8" +dependencies = [ + "dotenv", + "either", + "heck", + "once_cell", + "proc-macro2", + "quote", + "serde_json", + "sha2 0.9.9", + "sqlx-core", + "sqlx-rt", + "syn", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" +dependencies = [ + "native-tls", + "once_cell", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +dependencies = [ + "itoa 1.0.1", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" +dependencies = [ + "bytes 1.1.0", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes 1.1.0", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +dependencies = [ + "lazy_static", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber 0.3.8", +] + +[[package]] +name = "tracing-log" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74786ce43333fcf51efe947aed9718fbe46d5c7328ec3f1029e818083966d9aa" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typed-headers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3179a61e9eccceead5f1574fd173cf2e162ac42638b9bf214c6ad0baf7efa24a" +dependencies = [ + "base64 0.11.0", + "bytes 0.5.6", + "chrono", + "http", + "mime", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust-api/Cargo.toml b/rust-api/Cargo.toml new file mode 100644 index 0000000..0e3648c --- /dev/null +++ b/rust-api/Cargo.toml @@ -0,0 +1,33 @@ +[package] +edition = "2021" +name = "rust-api" +version = "0.1.0" + +[dependencies] +anyhow = "1.0.53" +color-eyre = "0.6.0" +dotenv = "0.15.0" +poem = "1.2.47" +rand = "*" +serde_json = "1.0.79" +tracing = "*" +tracing-subscriber = "0.2.24" +jwt = "0.15.0" +sha2 = "0.9" +hmac = "0.11" +serde = "1.0.136" + +[dependencies.poem-openapi] +features = ["swagger-ui", "url"] +version = "1.2.47" + +[dependencies.sqlx] +features = ["runtime-tokio-native-tls", "postgres", "json"] +version = "0.5" + +[dependencies.tokio] +anyhow = "1.0.53" +dotenv = "0.15.0" +features = ["macros", "rt-multi-thread"] +serde_json = "1.0.79" +version = "1.12.0" diff --git a/rust-api/Dockerfile b/rust-api/Dockerfile new file mode 100644 index 0000000..32d32c4 --- /dev/null +++ b/rust-api/Dockerfile @@ -0,0 +1,17 @@ +FROM rust + +# We create a new empty shell project to fake the dependencies so we can cache them +WORKDIR /code +RUN USER=root cargo new --bin rust-api + +COPY ./Cargo.lock ./Cargo.lock +COPY ./Cargo.toml ./Cargo.toml + +RUN cargo build --release +RUN rm src/*.rs + +COPY ./src ./src + +RUN cargo install --path . + +CMD ["rust-api"] diff --git a/rust-api/Makefile b/rust-api/Makefile new file mode 100644 index 0000000..505ff23 --- /dev/null +++ b/rust-api/Makefile @@ -0,0 +1,13 @@ +## +# Rust API Spike +## + +run: deps + docker-compose up -d + cargo watch -c -x run + +deps: + @echo "Checking dependencies..." + @which docker-compose || echo "Please install docker-compose" + @which cargo || echo "Please install cargo from rustup.rs" + @cargo watch --version || cargo install cargo-watch -q diff --git a/rust-api/README.md b/rust-api/README.md new file mode 100644 index 0000000..de53ce4 --- /dev/null +++ b/rust-api/README.md @@ -0,0 +1,39 @@ +# Rust spike of the forms-api-prototype + +## prerequisites + +Rust and either a local Postgres, or Docker. + +### Rust + +Install the rust toolchain from https://sh.rustup.rs with: + +``` shell +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +### Docker + +If you don't have Docker, install it by following the instructions here: https://docs.docker.com/get-docker/ + +### Postgres + +Though Docker is a cleaner way to run Postgres, any local Postgres db will work for testing. +The installation and configuration of which is left as an exercise for the user. Look in `docker-compose.yaml` for the credentials and db we expect. + +## Running the server + + +Please make sure your postgres db is up before starting the server, to do this with the included docker config is simply: + +``` shell +docker-compose up +``` + +Then when your postgres is up, however you have done that, start the api server: + +```shell +cargo run +``` + + diff --git a/rust-api/docker-compose.yaml b/rust-api/docker-compose.yaml new file mode 100644 index 0000000..0b9ecb8 --- /dev/null +++ b/rust-api/docker-compose.yaml @@ -0,0 +1,13 @@ +version: "3.9" +services: + db: + image: postgres + environment: + POSTGRES_USERNAME: postgres + POSTGRES_PASSWORD: password + ports: + - "5432:5432" + volumes: + - rust-api-pgdata:/var/lib/postgresql/data/ +volumes: + rust-api-pgdata: {} diff --git a/rust-api/example_forms/get-condition-evaluation-context b/rust-api/example_forms/get-condition-evaluation-context new file mode 100644 index 0000000..015d4bd --- /dev/null +++ b/rust-api/example_forms/get-condition-evaluation-context @@ -0,0 +1,678 @@ +{ + "startPage": "/uk-passport", + "pages": [ + { + "path": "/uk-passport", + "components": [ + { + "type": "YesNoField", + "name": "ukPassport", + "title": "Do you have a UK passport?", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "section": "checkBeforeYouStart", + "next": [ + { + "path": "/how-many-people" + }, + { + "path": "/anothertest", + "condition": "WLkGmF" + }, + { + "path": "/testconditions", + "condition": "doesntHaveUKPassport" + } + ], + "title": "Do you have a UK passport?" + }, + { + "path": "/how-many-people", + "section": "applicantDetails", + "components": [ + { + "options": { + "classes": "govuk-input--width-10", + "required": true + }, + "type": "SelectField", + "name": "numberOfApplicants", + "title": "How many applicants are there?", + "list": "numberOfApplicants", + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-one-name" + } + ], + "title": "How many applicants are there?" + }, + { + "path": "/applicant-one-name", + "title": "Applicant 1", + "section": "applicantOneDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-one-address" + } + ] + }, + { + "path": "/applicant-one-address", + "section": "applicantOneDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-two", + "condition": "moreThanOneApplicant" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-two", + "title": "Applicant 2", + "section": "applicantTwoDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-two-address" + } + ] + }, + { + "path": "/applicant-two-address", + "section": "applicantTwoDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-three", + "condition": "moreThanTwoApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-three", + "title": "Applicant 3", + "section": "applicantThreeDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-three-address" + } + ] + }, + { + "path": "/applicant-three-address", + "section": "applicantThreeDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-four", + "condition": "moreThanThreeApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-four", + "title": "Applicant 4", + "section": "applicantFourDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": { + + } + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/applicant-four-address" + } + ] + }, + { + "path": "/applicant-four-address", + "section": "applicantFourDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/contact-details", + "section": "applicantDetails", + "components": [ + { + "type": "TelephoneNumberField", + "name": "phoneNumber", + "title": "Phone number", + "hint": "If you haven't got a UK phone number, include country code", + "options": { + "required": true + }, + "schema": { + + } + }, + { + "type": "EmailAddressField", + "name": "emailAddress", + "title": "Your email address", + "options": { + "required": true + }, + "schema": { + + } + } + ], + "next": [ + { + "path": "/testconditions" + } + ], + "title": "Applicant contact details" + }, + { + "path": "/summary", + "controller": "./pages/summary.js", + "title": "Summary", + "components": [ + + ], + "next": [ + + ] + }, + { + "path": "/testconditions", + "title": "TestConditions", + "components": [ + { + "name": "pmmRYP", + "options": { + "condition": "bDDfgf" + }, + "type": "Para", + "content": "There Is Someone Called Applicant", + "schema": { + + } + } + ], + "next": [ + { + "path": "/summary" + } + ] + }, + { + "path": "/anothertest", + "title": "AnotherTest", + "components": [ + { + "name": "FnMsqX", + "options": { + + }, + "type": "Para", + "content": "Another Page" + } + ], + "next": [ + { + "path": "/summary" + } + ] + } + ], + "lists": [ + { + "name": "numberOfApplicants", + "title": "Number of people", + "type": "number", + "items": [ + { + "text": "1", + "value": 1, + "description": "", + "condition": "" + }, + { + "text": "2", + "value": 2, + "description": "", + "condition": "" + }, + { + "text": "3", + "value": 3, + "description": "", + "condition": "" + }, + { + "text": "4", + "value": 4, + "description": "", + "condition": "" + } + ] + } + ], + "sections": [ + { + "name": "checkBeforeYouStart", + "title": "Check before you start" + }, + { + "name": "applicantDetails", + "title": "Applicant details" + }, + { + "name": "applicantOneDetails", + "title": "Applicant 1" + }, + { + "name": "applicantTwoDetails", + "title": "Applicant 2" + }, + { + "name": "applicantThreeDetails", + "title": "Applicant 3" + }, + { + "name": "applicantFourDetails", + "title": "Applicant 4" + } + ], + "phaseBanner": { + + }, + "fees": [ + + ], + "outputs": [ + { + "name": "Ric43H5Ctwl4NBDC9x1_4", + "title": "email", + "type": "email", + "outputConfiguration": { + "emailAddress": "jennifermyanh.duong@digital.homeoffice.gov.uk" + } + } + ], + "declaration": "All the answers you have provided are true to the best of your knowledge.
", + "version": 2, + "conditions": [ + { + "name": "hasUKPassport", + "displayName": "hasUKPassport", + "value": "checkBeforeYouStart.ukPassport==true" + }, + { + "name": "moreThanOneApplicant", + "displayName": "moreThanOneApplicant", + "value": "applicantDetails.numberOfApplicants > 1" + }, + { + "name": "moreThanTwoApplicants", + "displayName": "moreThanTwoApplicants", + "value": "applicantDetails.numberOfApplicants > 2" + }, + { + "name": "moreThanThreeApplicants", + "displayName": "moreThanThreeApplicants", + "value": "applicantDetails.numberOfApplicants > 3" + }, + { + "displayName": "Another", + "name": "nAQyYp", + "value": { + "name": "Another", + "conditions": [ + { + "conditionName": "doesntHaveUKPassport", + "conditionDisplayName": "doesntHaveUKPassport" + } + ] + } + }, + { + "displayName": "Another2", + "name": "QFdzTQ", + "value": { + "name": "Another2", + "conditions": [ + { + "field": { + "name": "checkBeforeYouStart.ukPassport", + "type": "YesNoField", + "display": "Do you have a UK passport?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "true", + "display": "true" + } + } + ] + } + }, + { + "displayName": "Another3", + "name": "WLkGmF", + "value": { + "name": "Another3", + "conditions": [ + { + "field": { + "name": "applicantOneDetails.firstName", + "type": "TextField", + "display": "First name" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Applicant", + "display": "Applicant" + } + }, + { + "coordinator": "and", + "field": { + "name": "checkBeforeYouStart.ukPassport", + "type": "YesNoField", + "display": "Do you have a UK passport?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "false", + "display": "false" + } + } + ] + } + }, + { + "name": "bDDfgf", + "displayName": "testCondition", + "value": { + "name": "testCondition", + "conditions": [ + { + "field": { + "name": "applicantOneDetails.firstName", + "type": "TextField", + "display": "First name" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Applicant", + "display": "Applicant" + } + } + ] + } + }, + { + "name": "doesntHaveUKPassport", + "displayName": "doesntHaveUKPassport", + "value": "checkBeforeYouStart.ukPassport==false" + } + ], + "skipSummary": false +} diff --git a/rust-api/example_forms/report-a-terrorist b/rust-api/example_forms/report-a-terrorist new file mode 100644 index 0000000..d2eabf6 --- /dev/null +++ b/rust-api/example_forms/report-a-terrorist @@ -0,0 +1,281 @@ +{ + "startPage": "/do-you-have-a-link-to-the-evidence", + "pages": [ + { + "title": "Do you have a link to the evidence?", + "path": "/do-you-have-a-link-to-the-evidence", + "components": [ + { + "name": "UjidZI", + "options": {}, + "type": "Para", + "content": "It’s helpful if you can send us links to the relevant pages, or posts if it was posted on social media.", + "schema": {} + }, + { + "name": "rfUYC", + "options": {}, + "type": "Details", + "title": "Help me find the link", + "content": "If you’re on a website, the link appears in the bar at the top of the page. An example of a link is, www.gov.uk/page/1234/content#.", + "schema": {} + }, + { + "type": "RadiosField", + "title": "Do you have a link to the material?", + "options": { + "hideTitle": true + }, + "name": "doyouhavealink", + "schema": {}, + "list": "HTbt4V" + } + ], + "next": [ + { + "path": "/do-you-have-any-evidence" + }, + { + "path": "/yes-i-have-a-link-to-the-material", + "condition": "b-NGgWvGISkJJLuzsJIjv" + } + ], + "section": "PMXq1s" + }, + { + "path": "/do-you-have-any-evidence", + "title": "Do you have any evidence?", + "components": [ + { + "name": "OQrrkG", + "options": {}, + "type": "Para", + "content": "This could be an image or video, for example. Evidence is helpful should the material be deleted before we can find it.It’s safe to save evidence to your device for the purpose of reporting it to us. We recommend deleting it afterwards.", + "schema": {} + }, + { + "name": "3jdOpV", + "options": {}, + "type": "Details", + "title": "Help me take a screenshot", + "content": "Try this:Press the Shift key (⇧), command (or Cmd), and 3The screenshot will be saved to your DesktopYou can now upload it to the formTry this:Press the Ctrl key and the switch window keyThe screenshot will be saved to your DownloadsYou can now upload it to the formIf that doesn’t work, try pressing Ctrl and F5.When viewing the material:Press the Prt Scr key (or similar) to take a copy of your screenPaste the image into Microsoft Paint or a similar applicationSave the file to your computerUpload the file to the formIf that doesn’t work, you may need to search for how to take screenshots on your particular computer model.", + "schema": {} + }, + { + "name": "LU6RMD", + "options": {}, + "type": "RadiosField", + "title": "Do you have any evidence?", + "schema": {}, + "list": "mdmRq9" + } + ], + "next": [ + { + "path": "/is-there-anything-else-you-can-tell-us" + }, + { + "path": "/yes-i-have-evidence", + "condition": "On5IOaSRDSyLs1G7-Dmdy" + } + ], + "section": "PMXq1s" + }, + { + "title": "summary", + "path": "/summary", + "controller": "./pages/summary.js", + "components": [] + }, + { + "path": "/is-there-anything-else-you-can-tell-us", + "title": "Is there anything else you can tell us?", + "components": [ + { + "name": "HETM3o", + "options": {}, + "type": "Para", + "content": "Details may include:who shared the materialwhen it was shareda description, if you haven’t provided a link or evidence", + "schema": {} + }, + { + "name": "evZ-IJ", + "options": { + "required": false + }, + "type": "MultilineTextField", + "title": "Additional Info", + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ], + "section": "PMXq1s" + }, + { + "path": "/yes-i-have-a-link-to-the-material", + "title": "Yes I have a link to the material", + "components": [ + { + "type": "MultilineTextField", + "title": "Link to the material", + "hint": "Please put in the link to the material here", + "name": "blarGGH", + "options": {}, + "schema": {} + } + ], + "next": [ + { + "path": "/do-you-have-any-evidence" + } + ], + "section": "PMXq1s" + }, + { + "path": "/yes-i-have-evidence", + "title": "Yes I have evidence", + "components": [ + { + "name": "koE_ae", + "options": { + "required": false + }, + "type": "FileUploadField", + "title": "Evidence File Upload", + "hint": "Please upload your evidence here", + "schema": {} + } + ], + "next": [ + { + "path": "/is-there-anything-else-you-can-tell-us" + } + ], + "section": "PMXq1s" + } + ], + "lists": [ + { + "title": "linktomateriallist", + "name": "HTbt4V", + "type": "string", + "items": [ + { + "text": "Yes, I do have a link", + "value": "yes" + }, + { + "text": "No, I don't have a link", + "value": "no" + } + ] + }, + { + "title": "evidencelist", + "name": "mdmRq9", + "type": "string", + "items": [ + { + "text": "Yes, I have evidence", + "value": "yes" + }, + { + "text": "No, I don't have evidence", + "value": "no" + } + ] + } + ], + "sections": [ + { + "name": "PMXq1s", + "title": "Evidence" + } + ], + "phaseBanner": {}, + "metadata": {}, + "fees": [], + "outputs": [ + { + "name": "q7mMOb6Eu6EauibjcTFT3", + "title": "powerapps", + "type": "webhook", + "outputConfiguration": { + "url": "https://prod-182.westeurope.logic.azure.com:443/workflows/cfa66b774dad40459bf36e334d860445/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=4nNQTOYk5DnEByQSKMb5jzu_cXJ0NKJuH4KZGBiqvMk" + } + } + ], + "version": 2, + "conditions": [ + { + "name": "b-NGgWvGISkJJLuzsJIjv", + "displayName": "hasLink", + "value": { + "name": "hasLink", + "conditions": [ + { + "field": { + "name": "PMXq1s.doyouhavealink", + "type": "RadiosField", + "display": "Do you have a link to the material? in PMXq1s" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "yes", + "display": "Yes, I do have a link" + } + } + ] + } + }, + { + "name": "xY51EDbc4lPr6kHZl1umG", + "displayName": "noEvidence", + "value": { + "name": "noEvidence", + "conditions": [ + { + "field": { + "name": "PMXq1s.LU6RMD", + "type": "RadiosField", + "display": "Do you have any evidence? in PMXq1s" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "no", + "display": "No, I don't have evidence" + } + } + ] + } + }, + { + "name": "On5IOaSRDSyLs1G7-Dmdy", + "displayName": "hasEvidence", + "value": { + "name": "hasEvidence", + "conditions": [ + { + "field": { + "name": "PMXq1s.LU6RMD", + "type": "RadiosField", + "display": "Do you have any evidence? in PMXq1s" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "yes", + "display": "Yes, I have evidence" + } + } + ] + } + } + ] +} diff --git a/rust-api/example_forms/runner-components-test b/rust-api/example_forms/runner-components-test new file mode 100644 index 0000000..3831649 --- /dev/null +++ b/rust-api/example_forms/runner-components-test @@ -0,0 +1,379 @@ +{ + "startPage": "/do-you-own-a-vehicle", + "pages": [ + { + "title": "Do you own a vehicle?", + "path": "/do-you-own-a-vehicle", + "components": [ + { + "name": "qqbRw1", + "options": {}, + "type": "YesNoField", + "title": "Do you own a vehicle?", + "values": { + "type": "listRef" + }, + "schema": {} + }, + { + "name": "LdOljB", + "options": {}, + "type": "InsetText", + "content": "It does not matter what you pick as it will redirect you to the same page", + "schema": {} + } + ], + "next": [ + { + "path": "/what-address-is-the-vehicle-registered-to" + } + ] + }, + { + "path": "/what-address-is-the-vehicle-registered-to", + "title": "What address is the vehicle registered to?", + "components": [ + { + "name": "sFR4aX", + "options": {}, + "type": "UkAddressField", + "title": "What address is the vehicle registered to?", + "schema": {} + }, + { + "name": "tVlnZa", + "options": {}, + "type": "DateField", + "title": "What date was the vehicle registered at this address?", + "schema": {} + }, + { + "name": "Z0Guyn", + "options": {}, + "type": "CheckboxesField", + "title": "Which Clean Air Zones are you claiming an exemption for?", + "list": "O2uEB1", + "hint": "Please check all that apply, however you are restricted to a maximum of two choices.", + "schema": {} + }, + { + "name": "M8gMK7", + "options": { + "required": false + }, + "type": "FileUploadField", + "title": "Proof of address", + "hint": "This can be a drivers licence or utility bill dated with the last month", + "schema": {} + } + ], + "next": [ + { + "path": "/details-about-your-vehicle" + } + ] + }, + { + "path": "/clean-air-zone-caz-exemption", + "title": "Clean Air Zone (CAZ) Exemption", + "components": [ + { + "name": "MOB13t", + "options": {}, + "type": "Para", + "content": "How to check if you're exempt from paying a charge and how to create a business account, and what support or exemptions are available. ", + "schema": {} + } + ], + "next": [ + { + "path": "/do-you-own-a-vehicle" + } + ], + "controller": "./pages/start.js" + }, + { + "path": "/details-about-your-vehicle", + "title": "Details about your vehicle", + "components": [ + { + "name": "0ZVmN_", + "options": {}, + "type": "AutocompleteField", + "title": "What is the make of you vehicle?", + "list": "-HMHHj", + "schema": {} + }, + { + "name": "gHSgo2", + "options": {}, + "type": "TextField", + "title": "Vehicle Model", + "hint": "For example A1, 740, Elantra", + "schema": {} + }, + { + "name": "4LZ9to", + "options": {}, + "type": "DatePartsField", + "title": "Date you purchased the vehicle?", + "schema": {} + }, + { + "type": "RadiosField", + "title": "What fuel type does your vehicle use?", + "list": "sm_ssM", + "name": "fsfsdfsdf", + "nameHasError": false, + "options": {}, + "schema": {} + }, + { + "name": "chYCuk", + "options": {}, + "type": "MultilineTextField", + "title": "Has the vehicle been modified in any way?", + "hint": "Failure to declare modifications will result in severe penalties if not disclosed at this point.", + "schema": {} + } + ], + "next": [ + { + "path": "/driver-details" + } + ] + }, + { + "path": "/driver-details", + "title": "Driver details", + "components": [ + { + "name": "wJzPKE", + "options": {}, + "type": "NumberField", + "title": "How many people in your household drive this vehicle?", + "schema": {} + }, + { + "name": "PNIThU", + "options": {}, + "type": "TextField", + "title": "Full name of the main driver", + "hint": "Please exclude your title", + "schema": {} + }, + { + "name": "0zL5bB", + "options": {}, + "type": "TelephoneNumberField", + "title": "Contact number", + "hint": "Landline or mobile", + "schema": {} + } + ], + "next": [ + { + "path": "/final-steps" + } + ] + }, + { + "path": "/final-steps", + "title": "final steps", + "components": [ + { + "name": "fkd8av", + "options": {}, + "type": "List", + "title": "Declaration", + "list": "mJHWaC", + "schema": {} + }, + { + "name": "L_2AYe", + "options": {}, + "type": "EmailAddressField", + "title": "Your email address", + "hint": "We will send confirmation of your application to the provided email address", + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ] + }, + { + "path": "/summary", + "title": "Summary", + "components": [], + "next": [], + "controller": "./pages/summary.js" + } + ], + "lists": [ + { + "title": "Vehicle Type", + "name": "ckrDmV", + "type": "string", + "items": [ + { + "text": "Car", + "value": 1 + }, + { + "text": "4 x 4/SUV", + "value": 2 + }, + { + "text": "Van", + "value": 3 + }, + { + "text": "Motorbike/Moped", + "value": 4 + } + ] + }, + { + "title": "Vehicle Make", + "name": "-HMHHj", + "type": "string", + "items": [ + { + "text": "Alfa Romeo", + "value": 1 + }, + { + "text": "BMW", + "value": 2 + }, + { + "text": "Ford", + "value": 3 + }, + { + "text": "Citroen", + "value": 4 + }, + { + "text": "Nissan", + "value": 5 + }, + { + "text": "Honda", + "value": 6 + }, + { + "text": "Mercedes", + "value": 8 + }, + { + "text": "Audi", + "value": 9 + }, + { + "text": "Toyota", + "value": 10 + }, + { + "text": "Hyundai", + "value": 11 + }, + { + "text": "Kia", + "value": 12 + } + ] + }, + { + "title": "Fuel types", + "name": "sm_ssM", + "type": "string", + "items": [ + { + "text": "Diesel", + "value": 1 + }, + { + "text": "Electric", + "value": 2 + }, + { + "text": "Hydrogen", + "value": 3 + }, + { + "text": "Petrol", + "value": 4 + }, + { + "text": "Hybrid", + "value": 5 + } + ] + }, + { + "title": "CAZ Location", + "name": "O2uEB1", + "type": "string", + "items": [ + { + "text": "Bath", + "value": 1 + }, + { + "text": "Bristol", + "value": 2 + }, + { + "text": "Birmingham", + "value": 3 + }, + { + "text": "Cardiff", + "value": 4 + }, + { + "text": "Liverpool", + "value": 6 + }, + { + "text": "Leeds", + "value": 7 + }, + { + "text": "Manchester", + "value": 8 + } + ] + }, + { + "title": "Declaration", + "name": "mJHWaC", + "type": "string", + "items": [ + { + "text": "You are not a Robot", + "value": 1 + }, + { + "text": "You have not previously claimed an exemption", + "value": 2 + }, + { + "text": "You have not omitted or purposely witheld information that might be detrimental to you claim", + "value": 3 + } + ] + } + ], + "sections": [], + "phaseBanner": {}, + "metadata": {}, + "fees": [], + "outputs": [], + "version": 2, + "conditions": [] +} \ No newline at end of file diff --git a/rust-api/example_forms/test b/rust-api/example_forms/test new file mode 100644 index 0000000..59b6701 --- /dev/null +++ b/rust-api/example_forms/test @@ -0,0 +1,509 @@ +{ + "startPage": "/start", + "pages": [ + { + "title": "Start", + "path": "/start", + "components": [], + "next": [ + { + "path": "/uk-passport" + } + ], + "controller": "./pages/start.js" + }, + { + "path": "/uk-passport", + "components": [ + { + "type": "YesNoField", + "name": "ukPassport", + "title": "Do you have a UK passport?", + "options": { + "required": true + }, + "schema": {} + } + ], + "section": "checkBeforeYouStart", + "next": [ + { + "path": "/how-many-people" + }, + { + "path": "/no-uk-passport", + "condition": "doesntHaveUKPassport" + } + ], + "title": "Do you have a UK passport?" + }, + { + "path": "/no-uk-passport", + "title": "You're not eligible for this service", + "components": [ + { + "type": "Para", + "content": "If you still think you're eligible please contact the Foreign and Commonwealth Office.", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [] + }, + { + "path": "/how-many-people", + "section": "applicantDetails", + "components": [ + { + "options": { + "classes": "govuk-input--width-10", + "required": true + }, + "type": "SelectField", + "name": "numberOfApplicants", + "title": "How many applicants are there?", + "list": "numberOfApplicants" + } + ], + "next": [ + { + "path": "/applicant-one" + } + ], + "title": "How many applicants are there?" + }, + { + "path": "/applicant-one", + "title": "Applicant 1", + "section": "applicantOneDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-one-address" + } + ] + }, + { + "path": "/applicant-one-address", + "section": "applicantOneDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-two", + "condition": "moreThanOneApplicant" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-two", + "title": "Applicant 2", + "section": "applicantTwoDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-two-address" + } + ] + }, + { + "path": "/applicant-two-address", + "section": "applicantTwoDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-three", + "condition": "moreThanTwoApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-three", + "title": "Applicant 3", + "section": "applicantThreeDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-three-address" + } + ] + }, + { + "path": "/applicant-three-address", + "section": "applicantThreeDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-four", + "condition": "moreThanThreeApplicants" + }, + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/applicant-four", + "title": "Applicant 4", + "section": "applicantFourDetails", + "components": [ + { + "type": "Para", + "content": "Provide the details as they appear on your passport.", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "TextField", + "name": "firstName", + "title": "First name", + "options": { + "required": true + }, + "schema": {} + }, + { + "options": { + "required": false, + "optionalText": false + }, + "type": "TextField", + "name": "middleName", + "title": "Middle name", + "hint": "If you have a middle name on your passport you must include it here", + "schema": {} + }, + { + "type": "TextField", + "name": "lastName", + "title": "Surname", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/applicant-four-address" + } + ] + }, + { + "path": "/applicant-four-address", + "section": "applicantFourDetails", + "components": [ + { + "type": "UkAddressField", + "name": "address", + "title": "Address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/contact-details" + } + ], + "title": "Address" + }, + { + "path": "/contact-details", + "section": "applicantDetails", + "components": [ + { + "type": "TelephoneNumberField", + "name": "phoneNumber", + "title": "Phone number", + "hint": "If you haven't got a UK phone number, include country code", + "options": { + "required": true + }, + "schema": {} + }, + { + "type": "EmailAddressField", + "name": "emailAddress", + "title": "Your email address", + "options": { + "required": true + }, + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ], + "title": "Applicant contact details" + }, + { + "path": "/summary", + "controller": "./pages/summary.js", + "title": "Summary", + "components": [], + "next": [] + } + ], + "lists": [ + { + "name": "numberOfApplicants", + "title": "Number of people", + "type": "number", + "items": [ + { + "text": "1", + "value": 1, + "description": "", + "condition": "" + }, + { + "text": "2", + "value": 2, + "description": "", + "condition": "" + }, + { + "text": "3", + "value": 3, + "description": "", + "condition": "" + }, + { + "text": "4", + "value": 4, + "description": "", + "condition": "" + } + ] + } + ], + "sections": [ + { + "name": "checkBeforeYouStart", + "title": "Check before you start" + }, + { + "name": "applicantDetails", + "title": "Applicant details" + }, + { + "name": "applicantOneDetails", + "title": "Applicant 1" + }, + { + "name": "applicantTwoDetails", + "title": "Applicant 2" + }, + { + "name": "applicantThreeDetails", + "title": "Applicant 3" + }, + { + "name": "applicantFourDetails", + "title": "Applicant 4" + } + ], + "phaseBanner": {}, + "fees": [], + "payApiKey": "", + "outputs": [ + { + "name": "Ric43H5Ctwl4NBDC9x1_4", + "title": "email", + "type": "email", + "outputConfiguration": { + "emailAddress": "jennifermyanh.duong@digital.homeoffice.gov.uk" + } + } + ], + "declaration": "All the answers you have provided are true to the best of your knowledge.
", + "version": 2, + "conditions": [ + { + "name": "hasUKPassport", + "displayName": "hasUKPassport", + "value": "checkBeforeYouStart.ukPassport==true" + }, + { + "name": "doesntHaveUKPassport", + "displayName": "doesntHaveUKPassport", + "value": "checkBeforeYouStart.ukPassport==false" + }, + { + "name": "moreThanOneApplicant", + "displayName": "moreThanOneApplicant", + "value": "applicantDetails.numberOfApplicants > 1" + }, + { + "name": "moreThanTwoApplicants", + "displayName": "moreThanTwoApplicants", + "value": "applicantDetails.numberOfApplicants > 2" + }, + { + "name": "moreThanThreeApplicants", + "displayName": "moreThanThreeApplicants", + "value": "applicantDetails.numberOfApplicants > 3" + } + ] +} diff --git a/rust-api/src/api.rs b/rust-api/src/api.rs new file mode 100644 index 0000000..09b552e --- /dev/null +++ b/rust-api/src/api.rs @@ -0,0 +1,213 @@ +use poem::{ + Request, + web::Data +}; +use poem_openapi::{ + param::Path, + payload::{Json, PlainText}, + Object, + OpenApi, + SecurityScheme, + auth::ApiKey, +}; +use serde_json::{json}; +use sqlx::{postgres::PgPool, Error}; +use std::{fs, path}; +use std::path::PathBuf; +use jwt::{VerifyWithKey}; +use serde::{Deserialize, Serialize}; +use hmac::{Hmac}; +use sha2::Sha256; + +use crate::forms; +use forms::Form; + +type ServerKey = Hmac