We hardcode this as second class for the moment but eventually
will let the user pick.
Currently the API appears to do no validation, e.g. a json
schema, that rejects API calls with the extra key for postage.
Next steps will be to put a PR into the API that will expect a
postage value in the request and save it with the rest of the
notification. Then when that is done we can add the user interface
to the admin app to let the user pick the postage.
Added a send button which only appears on the page if the query string
indicates that the PDF is valid. Before actually sending, we check that
the service has the right permissions and that the metadata for the
letter confirms the letter is valid (because the query string can be
changed).
Before, the delete decorator would delete the keys from Redis and then
we made the request to api to change the data. However, it is possible
that the cache could get re-populated in between these two things
happening, and so would cache outdated data.
This changes the order to send the api request first. We then always
delete the specified keys from Redis. Changing the order of the code in
the decorator changes the order in which the cache keys get deleted, so
the tests have been updated.
This report will be used by the engagement team. There is a form to give
a start and end date for the report, and the form is then downloaded
as a CSV file when the form is submitted.
This should make the ‘All organisations’ page load a lil’ bit quicker.
Still worth caching the domains separately so the response is smaller
when we only care about domains. This is because the code that uses the
domains is part of the sign up flow, so it’s really important that it’s
snappy.
Users can only be archived by Platform Admin from the user page
(/users/<user_id>). This removes them from all services and orgs and
updates their details.
The data flow of other bits of our application looks like this:
```
API (returns JSON)
⬇
API client (returns a built in type, usually `dict`)
⬇
Model (returns an instance, eg of type `Service`)
⬇
View (returns HTML)
```
The user API client was architected weirdly, in that it returned a model
directly, like this:
```
API (returns JSON)
⬇
API client (returns a model, of type `User`, `InvitedUser`, etc)
⬇
View (returns HTML)
```
This mixing of different layers of the application is bad because it
makes it hard to write model code that doesn’t have circular
dependencies. As our application gets more complicated we will be
relying more on models to manage this complexity, so we should make it
easy, not hard to write them.
It also means that most of our mocking was of the User model, not just
the underlying JSON. So it would have been easy to introduce subtle bugs
to the user model, because it wasn’t being comprehensively tested. A lot
of the changed lines of code in this commit mean changing the tests to
mock only the JSON, which means that the model layer gets implicitly
tested.
For those reasons this commit changes the user API client to return
JSON, not an instance of `User` or other models.
The domains lookup is a bit slow because it’s serialising all the
organisations in the database. Since we’re putting this in the sign up
flow it should feel snappy, so lets cache just the domain bit of it in
Redis.
We’re deprecating storing the domain as text on a branding in favour of
a database relationship between branding and organisation.
We need to do this now in order to remove the validation on these fields
(which depends on the data in `domains.yml`)
The api endpoint to get all template folders also returns the users who
can see each folder.
We need to clear the template-folder cache when adding a user to a service so
that we are not using out of date data about who can see each folder.
Added a folder permissions form to the page to invite users to services.
This only shows if the service has 'edit_folder_permissions' enabled,
and all folder checkboxes are checked by default. This change means that
InviteApiClient.create_invite now sends folder_permissions through to
notifications_api (so invites get created with folder permissions).
Started passing the folder_permissions through to notifications-api when
accepting an invite. This changes UserApiClient.add_user_to_service to
send folder_permissions to notifications_api so that new users get folder
permissions when they are added to the service.
We were already invitializing InvitedUser with folder_permissions
(defaulting to None), but this removes the default and adds
folder_permissions to the serialize method. Folder permissions should
now always be returned from api, either as an empty list or a list of
UUIDs.
The endpoint for adding a user to a service in api will now deal with
both user permissions and a user's folder permissions, so this changes
the format of the data we pass through.
The endpoint for setting permissions in api will now be used for both
user permissions and a user's folder permissions, so this changes the
format of the data we pass through.
when clients are defined in app/__init__.py, it increases the chance of
cyclical imports. By moving module level client singletons out to a
separate extensions file, we stop cyclical imports, but keep the same
code flow - the clients are still initialised in `create_app` in
`__init__.py`.
The redis client in particular is no longer separate - previously redis
was set up on the `NotifyAdminAPIClient` base class, but now there's one
singleton in `app.extensions`. This was done so that we can access redis
from outside of the existing clients.
This is a platform admin page which lists all letter brands and their
domain. Once the page to edit a letter brand has been created, each
brand will link to its edit page, but for now this is just a list of
brand names and domains.
This removes some code which is duplicative and obscure (ie it’s not
very clear why we do `"a" * 73` even though there is a Very Good Reason
for doing so).
We were getting all letter logos from a method in the email branding
client. Since we will be adding more client methods to deal with
letters, it makes things clearer to separate the email and letter
branding clients.
This commit adds logic to:
- take the list of selected folders and templates
- split it into two lists (of folders and templates)
- `POST` that data to the API, to effect the movement of said folders
and templates
I’ve tried to architect it in such a way that we can easily add more
template ‘operations’ in the future, as we add more forms to the choose
template page.
The add new templates page now has option to add template folders.
Tweaked wording of other options and h1 to clarify options since it's
not all about templates any more.
Added api client and stuff for it
This commit is the first step to disentangling the models from the API
clients. With the models in the same folder as the API clients it makes
it hard to import the API clients within the model without getting a
circular import.
After this commit the user API clients still has this problem, but at
least the service API client doesn’t.
`_get_current_service` is a function which gets called every time
`current_service` is referenced in a view method or Jinja template.
Because the service model was getting initialised inside this function
it was being reconstructed many times in one request. On the service
settings page, for example, it was getting initialised 43 times, adding
about 200ms to the response time.
This commit moves its initialisation to the point where we’re getting
the data from the API, which only happens once per request.
Pytest is deprecating the direct calling of fixtures. One fixture that
we call directly quite a lot is `fake_uuid`. Since it just returns the
value of `sample_uuid()` we can either call that instead (where we need
a fixed value) or generate a new UUID each time (where a fixed value is
not needed).
If we’re going to be referring to email branding as part of the service
creation journey then we should make sure it doesn’t slow things down
too much by adding an extra API call. Caching things in Redis is a way
of avoiding unneeded API calls.