This was broken because current_service doesn’t update itself after
calling the `update` method of the API. So we thought we were changing
the permissions like this:
```
{'email', 'sms', 'letter'}
{'email', 'sms', 'letter', 'broadcast'}
{'sms', 'letter', 'broadcast'}
{'letter', 'broadcast'}
{'broadcast'}
```
But actually we were doing this:
```
{'email', 'sms', 'letter'}
{'email', 'sms', 'letter', 'broadcast'}
{'sms', 'letter'}
{'email', 'letter'}
{'email', 'sms'}
```
This commit changes the code to update the permissions like this:
```
{'email', 'sms', 'letter'}
{'broadcast'}
```
It does so by adding a new method to the service model which changes all
the permissions in one API call, and updates the tests to mock the
underlying API call, not the method on the model.
When a service is switched over to broadcast it has the email, text
message and letter permissions removed. And the links to switch these
settings back on are hidden.
This commit ensures that even if the user manually goes to the URLs for
these pages, they still won’t be able to switch the other channels back
on.
To make the interface as simple as possible we don’t want to mix up
sending other types of communication where services have the broadcast
permission.
This commit removes the other permissions once a service has been given
the broadcast permission by a platform admin user.
We’re removing it for performance reasons.
This means removing the old pages that edited the letter contact block
when it was stored directly on the service, rather than the current
model where a service can have multiple contact blocks.
'Session expired' or similar makes it sound like a new error.
It could confuse the user and make them think the sign in didn't work
and that their session has expired again.
So we went with:
The change you made was not saved. Please try again.
When the admin app gets user objects from the API, these include a dict
of permissions by service for what the user can do to that services.
Permissions for inactive services are not included in the response as
per:
87cb6f2597/app/dao/permissions_dao.py (L66)
However, this causes a bug where a service is archived but cached user
data still tells us that the user has permissions to view the service.
This should not be the case and causes errors where users can still see
the archived service page, it's settings, and even request to go live
for it, because they are using old cached data for the user.
We solve this by deleting the users who are part of the service from the
cache.
We also delete the templates for this service from the cache as the
templates are also archived when we ask the API to archive the service
as per:
d95c0131e0/app/service/rest.py (L597)
Note, one decision I had to make was whether to delete the user cache
for just active team members or also invited users. Assuming an invited
user can't see the service until they've accepted their invite anyway, it
shouldn't make any difference whether we delete their cache or not.
A lot of pages in the admin app are now generated entirely from Redis,
without touching the API.
The one remaining API call that a lot of pages make, when the user is
platform admin or a member of an organisation, is to get the name of
the current service’s organisation.
This commit adds some code to start caching that as well, which should
speed up page load times for when we’re clicking around the admin app
(it’s typically 100ms just to get the organisation, and more than that
when the API is under load).
This means changing the service model to get the organisation from the
API by ID, not by service ID. Otherwise it would be very hard to clear
the cache if the name of the organisation ever changed.
We can’t cache the whole organisation because it has a
`count_of_live_services` field which can change at any time, without an
update being made.
Rather than hard-coding a format string in a bunch of different places
we can use the function we already have in utils.
This commit also refactors some logic around password resets to put the
date-parsing changes in the most sensible bit of the codebase, so it’s
clearer what the intention of the view-layer code is.
Celery/SQS underperforms in low-traffic environments. Tasks will sit on
celery queues for several seconds before getting picked up if they're
the only thing on the queue. This is observable in our test environments
like preview and staging, but we've got enough load on production that
this isn't an issue.
When we validate reply to email addresses, we expect a delivery receipt
to have been processed within 45 seconds of the button being pressed. On
preview, we often observe times over that, possibly due to the several
queues involved in sending an email and processing its receipt. So, to
ensure that functional tests can pass (when we don't really care how
fast things are, just that the flow doesn't break), bump this timeout up
to 120 seconds on preview. The functional tests were waiting for 120
seconds for the reply to address to be validated anyway.
Requests to go live and email branding requests come through to Zendesk
with tags attached automatically.
With the revised taxonomy some of these tags need to be updated, as
summarised in this spreadsheet.
In addition, `notify_action` tag has to be added in each of those cases.
Old|New
---|---
`notify_request_to_go_live_complete`|`notify_go_live_complete`
`notify_request_to_go_live_incomplete`|`notify_go_live_incomplete`
`notify_action_add_branding`|`notify_branding`
`notify_request_to_go_live_incomplete_mou`|`notify_go_live_incomplete_mou`
`notify_request_to_go_live`|`notify_go_live`
– https://docs.google.com/spreadsheets/d/1o5ATsFsVK8Qpj7x8QvxX-SfEuBZ75028GEySVcdBFYU/edit#gid=0
– https://www.pivotaltracker.com/story/show/169842970
We mostly rely on the API returning a 404 to generate 404s for trying
to get things with non-UUID IDs. This is fine, except our tests often
mock these API calls. So it could look like everything is working fine,
except the thing your passing in might never be a valid UUID, and thus
would 404 in a non-test environment.
So this commit:
1. uses the `uuid` URL converter everywhere there’s something that looks
like an ID in a URL parameter
2. adds a test which automates checking for 1.
Letting people input a bit of free text should reduce the amount of back
and forth we have to do over support tickets when setting up someone’s
branding.
If something else is the only option then we don’t show the radio button
at all and have just the free text input on the page (not behind a
progressive disclosure).
Users who work in local government can’t have GOV.UK branding on their
emails. And only those working for Companies House (for example) can
request the Companies House branding.
This commit adds:
- new choices of email branding, which offer the name of the branding,
rather than the style
- logic to filter this list to only the applicable options, based on
what we know about the user, service and organisation
This is a change from the previous approach which put the onus on users
to figure out the style of branding they wanted, when we might already
know that a lot of the options weren’t available to them, or would be
inconsistent with the branding of other services in their organisation.
We want GPs to be able to accept the agreement online. But at the moment
they don’t get automatically assigned to organisations. So we need to
let them enter the agreement accepting journey even if they don’t have
an organisation set up.
We added `Upload letters` to the platform admin service settings, which makes is confusing when next to `Upload documents`.
Also `User auth type editting` is a confusing label
`User auth type editting` --> `Email authentication`
`Uploading documents` --> `Send file by email`
The upload_letters permission can only be changed by Platform Admin
users. It works in a similar way to the inbound_sms nested permission
- you only see the row in the table if you have the 'letter' permission,
but the 'letter' and 'upload_letters' are still separate permissions and
changing one does not affect the other.
It’s possible to delete default letter contact blocks because there is a
fallback – having a blank letter contact block. This is different to SMS
senders and reply to addresses.
For this to make sense it also means:
- adding the ‘blank’ letter contact block to the list of letter contact
blocks
- having a way of setting the default back to being blank
The service organisation type will either be the same as the org type of
the service's organisation or will be set by a user when creating a new
service. This removes the ability to change it from the platform admin
settings table.
We used to give users the right version of the agreement by guessing
their organisation from their email address.
Now we do it by looking at the organisation of the service they’re
looking at.
In other words, users should only be downloading the agreement as part
of the go live journey, not outside it. This is because we think that
users will get confused if they download the agreement and:
- find there’s nowhere to physically sign it
- think that accepting the agreement is all they need to do to go live
Maintaining two paths to download the agreement also makes the code more
complicated, and makes it harder to update the content on these pages.
If we change our mind and decide whether a service should/should not be
counted in the list of live services then we should also drop the cache
which stores the count of how many live services there are.
If you’ve come from a template to add a new letter sender then it’s
because you want those words on that template. This commit adds the
extra API call to make that happen.
Most users don’t have multiple contact blocks. So by default it should
feel like you’re just editing the one contact block, rather than
managing a collection of them. So this page skips the ‘choose’ page when
the user doesn’t yet have any contact blocks.
Rather than force us to write the decorators in a specific order let’s
just have one decorator call the other. This should make fewer lines of
code, and fewer annoying test failures. It also means that the same way
of raising a `401` (through the `current_app` method) is used
everywhere.
At the moment we mostly have `user_has_permissions` execute first. It
shouldn’t matter, but it feels right for us to check that a user is
logged in before we check their permissions to a service. Otherwise a
malicious user could (maybe) check if a service ID belongs to a real
service, and go on to do something malicious with that information.
This commit adds some extra test code to enforce that the order is
always the same.
N.B. decorators in Python execute from closest to furthest (from the
line on which the function is defined).