This duplicates how the task list pattern is coded in the GOV.UK
Prototype kit[1]. It adds ARIA attributes and the use of a
semantically-meaningful element (`<strong>`) to give more information to
screen reader users.
1. https://govuk-prototype-kit.herokuapp.com/docs/templates/task-list
For some reason we are getting pending back as a status from one of
our text message providers.
Because this is unrecognised by the admin app it shows up in the list of
messages as the raw status, styled like an error.
This commit maps it to sending instead, because the user doesn’t need to
know or care about the difference.
A platform admin form accepts a list of references (one per line)
received from DVLA and sends them to the API to update notification
statuses.
References we get from DVLA start with `NOTIFY00\d`, which isn't
part of the reference we store in the database, so we remove them
before sending the data to the API.
The new `returned-letter` status should be treated as `delivered`
for now until we decide a way to display returned letters to users.
Having the service floating about as JSON is a bit flakey. Could easily
introduce a mistake where you mistype the name of a key and silently
get `None`.
Also means doing awkward things like `if 'permission' in
current_service['permissions']`, whereas for users we can do the
much cleaner `user.has_permission()`.
So this commit:
- introduces a model
- adds a `.has_permission` method similar to the one we have for users
The main task that we think ‘caseworker’ users do is send one off
messages.
So this commit:
- makes sure users who don’t have the `view_activity` permission (ie
not ‘admin’ users) can still send messages
- adds navigation so that these users have a place to go from which to
start the process of sending a one off message
In API, the endpoint for the new platform admin stats page has been
moved to a platform stats blueprint. This means we now need a platform
stats client.
A new platform admin page Email complaints has been added to surface those complaints.
Eventually the complaints will be visible to the services so they can remove the email address from their mailing list.
Next thing to implement is "x email complaints" warning on the platform admin summary page.
Updated notifications-utils. This brings in
- the renamed character sanitization classes
- the change to allow unicode in letter addresses (this lets us delete
a test that is no longer relevant)
Also replaced non-ascii characters in headers. This fixes a bug where
non-ascii characters in a CSV filename were causing errors since the
filename is also used in the header.
It is standard practice when using GOV.UK template to highlight the
selected navigation item in the propositional navigation (black bar) by
colouring it blue.
This commit adds a new subclass of `Navigation` with the mapping needed
to decide which pages belong to which item in the navigation (or none
at all).
Because we have multiple navigations, which will share the same methods
(by subclassing) but different mappings of navigation items to endpoints
by overriding the `.mapping` and `.exclude` attributes.
In research I’ve sometimes seen people click the wrong nav item. I
reckon that people’s concept of which pages live behind which navigation
items isn’t very strong.
We can reinforce this relationship by showing, for every page, which is
the corresponding nav item. The conventional way of doing this is either
with some kind of emphasis, typically colour or bold. I’ve gone for bold
because colour would be weird.
---
The implementation of this is quite loosely coupled to our application
code because:
- our application code is not well structured (eg we don’t make any use
of blueprints)
- spreading this change across lots of files in our application would
make it harder to test without actually hitting each endpoints; such
tests would be slow and verbose
So I’ve gone for more of a meta approach. Rather than testing that each
endpoint has a specific navigation item selected, I’ve gone for
validating that:
- all endpoints being mapped to are real
- all endpoints have _a_ selected navigation item (or are specifically
excluded)
This means that it’s impossible to add, change or remove an endpoint
without also updating which navigation item should be selected. And the
actual mapping is so declarative that it testing it would be redundant.
Previously, we were looking at the day of the week - so messages sent
six days ago would show up as "tomorrow". We now look at the actual
date, so that won't happen again.
We were also subtracting an hour to make 00:00 this evening show up as
"midnight today", despite it technically being tomorrow. However, this
means that 00:59 tomorrow morning would show up as "00:59 today", a
full day out. So reduce that to just a minute, so it doesn't affect
other times of day.
Precompiled letters can now have two additional states:
* pending-virus-check
* virus-scan-failed
Both new states should show in the notifications dashboard, and
virus-scan-failed should appear as an error state, with a descriptive
message. You should not be able to preview a letter in one of the two
new states, so the preview link has been removed for precompiled letters
in these states.
For text messages/emails it makes sense for ‘sending’ to be gray and
‘delivered’ to be black. But since we don’t show sending/delivered for
letters it doesn’t make sense for the text to change colour.
view args are parameters within the route. for example,
`/organisation/<org_id>/users`. If there is an org_id, then check that
the user is part of that organisation (users.organisations is a list of
all orgs that user is a member of).
* platform admins ignore this check if restrict_admin_usage=False
* if an endpoint has both org_id and service_id, org_id takes
precedence, but we should probably revisit this if we ever need
to create such an endpoint.
* you now call `@user_has_permissions()` with no arguments for
organisation endpoints - we can look at this if we decide we want
more clarity.
* you should never call user_has_permissions without any arguments
for endpoints that aren't organisation-based. We'll raise
NotImplementedError if you do.
However, by default, session cookies don't expire (only cleared out by
the end user's browser).
This is dumb. You'd think, given that there's
`config['PERMANENT_SESSION_LIFETIME']`, that you'd enable permanent
sessions in the config too - but no, you have to declare it for each
request. session.permanent is also, helpfully, a way of saying that the
session isn't permanent - in that, it will expire on its own, as
opposed to being controlled by the browser's session. Because session
is a proxy, it's only accessible from within a request context, so we
need to set this before every request 🙄http://flask.pocoo.org/docs/0.12/api/#flask.sessionhttps://stackoverflow.com/questions/34118093/flask-permanent-session-where-to-define-them
Refactor csrf handler into the normal error handler area, and then add
some tests to make sure it does the right thing. Also, change it back
to a 400, because the 403 err page talks about being in the wrong
place, but this is about sending the wrong data through, even though
it's technically a 403. Will need to think about wording but this is a
fine first pass
flask-script has been deprecated by the internal flask.cli module, but
making this carries a few changes with it
* you should add FLASK_APP=application.py and FLASK_DEBUG=1 to your
environment.sh.
* instead of using `python app.py runserver`, now you must run
`flask run -p 6012`. The -p command is important - the port must be
set before the config is loaded, so that it can live reload nicely.
(https://github.com/pallets/flask/issues/2113#issuecomment-268014481)
* find available commands by just running `flask`.
* run them using flask. eg `flask list_routes`
* define new tasks by giving them the decorator
`@app.cli.command('task-name')`. Task name isn't needed if it's just
the same as the function name. Alternatively, if app isn't available
in the current scope, you can invoke the decorator directly, as seen
in app/commands.py
In https://github.com/alphagov/notifications-admin/pull/1583 we changed
our Google Analytics settings to use newer browsers’ `sendBeacon`
feature. The advantage of this is that it
> [ensures] that the data has been sent during the unloading of a
> document [which] is something that has traditionally been difficult
> for developers
– https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
To transmit this data it uses a AJAX request (`XMLHttpRequest`)
underneath. AJAX requests are governed by the `connect-src` content
security policy (or the `default-src` if one is not present).
`connect-src`:
> Applies to XMLHttpRequest (AJAX), WebSocket or EventSource. If not
> allowed the browser emulates a 400 HTTP status code.
– https://content-security-policy.com/
Because we didn’t have one in place, `sendBeacon` requests to GA were
getting blocked in browsers that support content security policy (pretty
much everything better than IE11[1]).
1. https://caniuse.com/#feat=beacon