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.
Currently when you load the ‘edit user’ page (which has a URL like
`/service/<service_id>/users/<user_id>`) we check that:
- you belong to the service represented by `service_id`
- you have permission to edit users on this service
We don’t check that:
- the user represented by `user_id` belongs to this service
This means that if you could somehow determine another user’s `user_id`
(which I don’t think is possible if you don’t already have the manage
service permission for that service) then you could:
- edit their permissions on your service (weird, but wouldn’t have any
effect)
- change their email address (bad)
This commit adds checks to return a `404` any time you’re looking at a
service and trying to do stuff to a user who doesn’t belong to that
service.
We can’t add this check to the API easily because there are still times
that we want to get/modify users outside the context of a service (eg
platform admin pages, or users who have no services).
This works in a similar way to the create_letter_branding view function,
but with a few minor differences:
* Since we already have a file, uploading a file is no longer required
(since we can just use the current file if a new one is not uploaded)
* We save the changes in the database, then upload the new files to S3.
If saving to S3 raises an error, we now rollback the database changes to
prevent any errors when trying to view letters with the original logo.
it wouldn't show search if there were under a certain amount of letter
or email branding options - however we know there will always be more
than that amount so lets remove some complexity.
Also, rename the SearchTemplatesForm because it can search anything -
it just prompts you to search by name is all.
We have some teams who haver a series of files they have to send each
day. It’s easy to get muddled up and accidentally send the same file
again, if you think you haven’t already sent it.
This commit blocks you from sending the same combination of template
version and filename more than once on the same day[1].
This won’t affect teams who re-use the same template to give (for
example) updates on an incident for business continuity. These teams
edit the template between each send, thereby updating the version
number of the template.
1. This is based on how the `limit_days` argument to the API works - you
can dig into the code here: 2bd4f74ad0/app/dao/jobs_dao.py (L50)
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.
It’s inaccurate to have an estimated delivery date for letters sent
using a test key. We shouldn’t reassure people that:
- the letter won’t be printed
- (in the case of precompiled letters) that the letter has passed
validation
This can happen if you click a link for a service you don’t have access
to. We shouldn’t show the back to service link in this case because:
- you shouldn’t be able to find out the service’s name from just knowing
the link
- if you click the link you only get a `403` anyway
The new API response for template statistics returns separate
count for each status. We get rid of template stats for cancelled
notifications and group the rest of the statuses together.
Counting pages for API notifications takes a long time for services
with a lot of sent messages (since it issues a `count(*)` query for
the given filter). Since API message log doesn't have a "Next page"
link we can skip the count by setting a flag on the API request.
We already have a pattern for navigation folders and searching for
templates – let’s use it for the copy page too. And I reckon we can
represent services as folders if the user has multiple services they
could copy a template from.
Only users who work for government can accept the terms of use. This
will save us from having to email these requesters back telling them
they need to find someone else to submit the request.
Adds caching for service data retention. This removes separate API
client methods to retrieve individual data retention records by id
or type in favor of a single method that fetches and caches all
retention settings configured for the service. This makes it much
easier to invalidate cache when settings change.
Lookup by id or type is provided by helper methods in the service
model.
Since we’re letting users add new folders directly from the choose page
it makes sense that they should also be able to add templates from
there.
This resolves the problem we saw in user research where people found it
hard to know where to go to add a new folder when they were all behind
one green button.
None of our model or view layer code should need to know about accepted
invites. We don’t use them anywhere because once an invite is accepted
that person is now a user.
Putting this logic in the client means that:
- none of the code calling the client needs to care about accepted
invites
- it’s easier to (if we want) update the API code to not return accepted
invites
It’s redundant to make two API calls here, one to get all keys and one
to get a single key. Since the API calls are sequential we can speed
things up by getting the one key from the list of all keys.
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.
Clicking on template folder navigates to a page that displays that
folder's contents.
This reuses the existing choose template view by adding a filter
based on optional `template_folder_id` argument.
Service model methods are rewritten to match `all_templates` and
`get_template`. New `get_template_folder_path` method returns a
list of folders (from root to the current one) that the selected
folder is nested inside.
Currently the brandings have non-deterministic sorting, which means
the order changes from page load to page load. This makes it hard to
find the item you’re looking for.
This commit sorts them by the name of the branding, same as for email
brandings.
There’s a lot of code in service settings which:
- talks to the API directly through the clients
- passes that information through to the Jinja template
By encapsulating this logic in the service model:
- the Jinja template can access the data directly
- the logic can be reused across multiple methods
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.
One of the changes this pulls in is encoding of
periods in the token used for new password
requests.
In real-life the resulting URL is build by
concatenating the base url with the token so it
isn't processed further.
The test for new password requests builds the URL
with url_for. This encodes the result returned so
the periods are encoded twice.
Updated the 'get_sum_billing_units' function to no longer multiply the
billing units by the rate multiplier. The billing_units that come from
notifications-api already consist of the billable_units * rate_multiplier.
The rate_multiplier is also not returned from the api response anymore.
Also updated the billing mocks since these were not mocking the right fields in
the JSON responses from the API billing endpoints, and added the new
'postage' field which will get returned from the monthly-usage endpoint
in notifications-api.
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).
This is useful if you have lots of people sending messages and want to
report on who’s doing what.
Needs the API updating to return `created_by_name` in its response.
If a message has been sent with a test key it’s a bit confusing to just
say ‘Delivered’ on the page, because it hasn’t gone to anyone’s phone.
So this commit adds a bit of hint text to disambiguate what ‘Delivered’
actually means in this context.