- Requirements & Prereqs
- Wiki
- Validators
- Address/Street/Organisation Providers
- Payment Providers
- Storage Providers
- Running High Availability
- Structure Tests
- Preview
- Data Structure Preview
- dotnet core 3.1
- GPG key added to collaborators
IAddressProvider
is provided to enable integration with different address data sources.
The interface requires a ProviderName and a SearchAsync method which must return an AddressSearchResult
object.
string ProviderName { get; }
Task<IEnumerable<AddressSearchResult>> SearchAsync(string streetOrPostcode);
You can register new/multiple address providers in startup
services.AddSingleton<IAddressProvider, FakeAddressProvider>();
services.AddSingleton<IAddressProvider, CRMAddressProvider>();
services.AddSingleton<IAddressProvider, MyCustomAddressProvider>();
You can specify in the JSON form defenition for Address elements, which address provider you want use. To do this set AddressProvider
to the value of the required IAddressProvider.ProviderName
, for example to use a Provider with a ProviderName of "Fake";
{
"Type": "Address",
"Properties": {
"QuestionId": "address",
"AddressProvider": "Fake",
}
}
IStreetProvider
is provided to enable integration with different street level data sources.
Implementation is almost identical to that described in the AddressProvider
Register for use
services.AddSingleton<IStreetProvider, FakeStreetProvider>();
services.AddSingleton<IStreetProvider, CRMStreetProvider>();
return services;
Specify which street provider to use.
"Elements": [
{
"Type": "Street",
"Properties": {
"QuestionId": "customersstreet",
"StreetProvider": "Fake",
}
IOrganisationProvider
is provided to enable integration with different organisation data sources.
Implementation is almost identical to that described in the AddressProvider/StreetProvider, however Organisation Providers return an OrganisationSearchResult
Register for user
services.AddSingleton<IOrganisationProvider, FakeOrganisationProvider>();
services.AddSingleton<IOrganisationProvider, CRMOrganisationProvider>();
return services;
Specify which organisation provider to use.
{
"Type": "Organisation",
"Properties": {
"QuestionId": "organisation",
"Label": "Enter the organisation",
"OrganisationProvider": "Fake",
}
IPaymentProvider
is provided to enable integration with different payment systems, this assumes that you are redirected to an external payment provider where a payment is taken and then redirected back to the forms application to continue form processing.
The payment provider enables this on the method IPaymentProvider.GeneratePaymentUrl
which carries out any pre-payment actions, such as setting up payment/baskets etc. and the returns the URL to which form builder should direct the user.
The payment provider also abstracts the detail of understanding the payment response using the IPaymentProvider.VerifyPaymentResponse
method. The payment provider return nothing (if payment success) or throw an exception of type PaymentDeclinedException
or PaymentFailurexception
depending on the payment repsponse.
In order to maintain auditability and tracking the payments work flow enables an initial submission pre-payment, typically used to setup cases etc. and a further callback post payment to update cases, bookings etc. reflecting the result of the payment process.
Regsitering a payment provider for use
services.AddSingleton<IPaymentProvider, FakePaymentProvider>();
services.AddSingleton<IPaymentProvider, MyRealPaymentProvider>();
return services;
Specify which organisation provider to use.
{
"formName": [ "my-payment-form" ],
"PaymentProvider": "MyRealPay",
"settings": {
"accountReference": "our-account-reference",
"addressReference": "{{QUESTION:Address}}",
"name": "{{QUESTION:firstName}} {{QUESTION:lastName}}",
"email": "{{QUESTION:email}}",
"catalogueId": "our-catalog-id",
...
}
In order to enable a faster testing process of forms and formbuilder capability FakePaymentProvider
has been created. This functionality is turned off by default and should never be turned on in a production environment as it will effect every payment regardless of specified payment provider.
Fake payment will act exactly the same as any other payment provider in terms of input and output - but will allow the Tester/QA to specift the desired payment response (Success, Declined, Failure)
To turn fake payment on set the following value in the relevant environment configuration.
"PaymentConfiguration:FakePayment": true
As users submit data and move through forms the data they are submitting is temporarily stored before submission.
This function uses IDistributedCache.
Storage providers can be added from config and registered on app startup using.
services.AddStorageProvider(Configuration);
By default setup using config currently supports "Application", Distributed In Memory Cache (which ironically isn't actually distributed!), but allows us to develop locally and deploy to single instances.
This can be set up using the following config
{
"StorageProvider": {
"Type": "Application"
}
}
For a truly distributed we support Redis, this can be setup using the StorageProvider config below.
{
"StorageProvider": {
"Type": "Redis",
"Address": "YourRedisUrlHere",
"Instance": "YourPreferredInstanceNameHere"
}
}
If running in a load balanced environment you will need to be running a truly distributed cache (i.e. Redis).
In this case it's worth noting that for sessions to work correctly there needs to be a shared keystore.
Distributed cache and DataProtecton key storage specification is wrapped up in the services.AddStorageProvider(Configuration);
service registration (we should seperate this out!) so when you set storage provider to 'Redis' it also shares the data protection keys in redis as well (as per the code below).
var redis = ConnectionMultiplexer.Connect(storageProviderConfiguration["Address"]);
services.AddDataProtection().PersistKeysToStackExchangeRedis(redis, $"{storageProviderConfiguration["InstanceName"]}DataProtection-Keys");
Structure tests use Cypress to compare the DOM structure of components against snapshots. New structure tests should be added when a new component type is created. Existing tests may need to be modified, or snapshots replaced if the DOM structure of an existing component changes. More info on this feature can be found here
This section will be used to document the decisions made throughout the development process.
The formbuilder storage components will be provisioned by a Cloudformation stack. Jon H & Jake decided that the stack would include an S3 Bucket, IAM User and a User Policy to handle the storage of json files.
The example below shows the policy we manually created and applied to a test user:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutAccountPublicAccessBlock",
"s3:GetAccountPublicAccessBlock",
"s3:ListAllMyBuckets",
"s3:ListJobs",
"s3:CreateJob",
"s3:HeadBucket"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucketname/*",
"arn:aws:s3:::bucketname"
]
}
]
}
The S3 bucket used during testing was cofigured to 'Block all public access' to 'On'.
The bucket will be created using a Cloudformation template with the folder structure created by the template.
Preview allows you to view and validate a form without the need of uploading it to your configured Form schema provider. More info on this feature can be found here.
Data Structure Preview allows you to view the data structure that will be submitted to the form Service. More info on this feature can be found here
Analytic events can be enabled within appsettings.json Analytics
config section, by default this is GA but can be extended by creating your own IAnalyticsProvider
{
"Analytics": {
"Enabled": true,
"Type": "GA"
}
}
IAnalyticsProvider
is provided to enable integration with different analytics providers. The interface requires a ProviderName and a RaiseEventAsync method.
Analaytics event on successful form submission can be raised in the configured Analytics provider. More info on this feature can be found here