Commit 58cc1604a7 sanitises any non-ascii
characters in the headers. CSV filenames get used as a header value, so
this fixed a bug that occurred when non-ascii characters were used.
The CSV filename also gets used as part of the metadata when uploading
the file to S3. Since the S3 metadata can only contain ASII characters,
we also need to sanitise the filename before uploading it to S3.
This link is useful for people who are setting up templates and want to
test out how they look/how Notify works.
‘Caseworker’ users shouldn’t need to send themselves messages on a
regular basis, so this link is another thing we can take away.
Caseworkers skip the template page in their message sending journey.
Instead they go straight from picking a template to the first step of
sending. So the ‘Back’ link should send them straight back to the
picking a template page, skipping the individual template page (which
they don’t have permission to view).
If a template has a placeholder like `((email address))` then the sample
spreadsheet and CSV file have the email column twice.
Trying to upload this spreadsheet will result in a ‘duplicate column’
error.
This commit fixes it so that the column will only appear once.
We want to set the metadata on a file when rendering the check page, but
not when rendering the preview of a letter. So let’s put the code that
does that only in the place where we’re rendering the check page. This
means not having to pass a variable around.
Refactoring only; no functional changes.
When you upload a CSV the check page takes the file name from the URL
and writes it to the S3 metadata for that file.
This also happens when you go to the .png version of this page.
The .png version of the page doesn’t have the filename in the URL. So it
re-writes the S3 metadata with an empty filename.
This means that all letter jobs sent recently have no file names. This
commit fixes this problem.
we're not actually looking at the detailed service aspects - just
the stats. We're doing this in three places:
* dashboard
* notification activity page
* when checking jobs to see if we're over the daily limit
change these places to use a new api endpoint (service/id/statistics),
which hopefully be a little more performant, and will definitely be a
little more organised - moving away from generic endpoints with loads
of optional parameters.
We still need the detailed endpoints for the platform admin page tho.
Depends on https://github.com/alphagov/notifications-api/pull/1865
If a user clicks ‘back’ once they’ve sent a job we don’t want them to
land on the ‘check’ page again. This would suggest that they can send
the same job again (they can’t because that `job_id` is in the database
already). That said, it’s confusing to see that page; the natural thing
is to go jump back another step, to where you uploaded the file.
We’re going to stop storing job metadata in the session. So we can’t
rely on it for checking whether a file is valid. That safeguard is
happening in the API instead now (because it’s looking at the metadata
stored in S3).
S3 has a limit of 2kb for metadata:
> the user-defined metadata is limited to 2 KB in size. The size of
> user-defined metadata is measured by taking the sum of the number of
> bytes in the UTF-8 encoding of each key and value.
– https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#object-metadata
This means we have a limit of 1870 bytes for the filename:
```python
encoded = 'notification_count50000template_id665d26e7-ceac-4cc5-82ed-63d773d21561validTrueoriginal_file_name'.encode('utf-8')
sys.getsizeof(b)
>>> 130
2000-130
>>> 1870
```
Or, in other words, ~918 characters:
```python
sys.getsizeof(('ü'*918).encode('utf-8'))
>>> 1869
```
We’re getting the template just to get back its `id`, which is the one
thing we do know in order to get it.
The call to get template is still happening inside `_check_messages`, so
we’ll still catch someone trying to look at this page for a template
that doesn’t exist.
By doing this we no longer have to store it in the session. This is the
last thing that’s currently in the session, so removing it means we can
drop session storage for file uploads entirely.
Storing things in the session is proving buggy – we still have one user
(that we know about) where the session data isn’t getting written, so
they’re blocked from uploading a file.
Since all the info we’re storing in the session is about the file, it
makes sense to store it with the file.
This commit only does the writing of the metadata, once we’re sure this
is working we can do subsequent work to read it back, and remove
reliance on the session.
The check page expects template ID to be passed through in the URL not
the session now. The send test letter page wasn’t changed.
This commit changes it, and adds a test to make sure this path is
covered.
The start job endpoint needs the template ID in order to make the API
call.
It doesn’t make sense to add it to the start job URL, because users
could potentially start a job with the wrong template by hacking the URL
(which would blow up at some point, if the template didn’t match the
columns in the file).
A of this commit’s parent we are storing `template_id` and
`original_file_name` in the URL. Getting them from the URL is better,
so the check page no longer needs to look for them in the session. This
commit removes the code that looks for these values in the session.
At the moment you can’t press refresh on the check page if there’s
errors. This is because the session gets cleared when there’s errors.
This is a bad user experience.
The data that this page is relying on (from the session) is:
- template ID
- original file name
Neither of these things need to be in the session because:
- they are not secret
- the user can modify them already (by choosing a different template or
renaming their file locally)
So this commit additionally stores them in the URL.
if a user signs in again, clear their file upload data from any
aborted journeys from before, so that their cookies don't fill up
also add some temporary logging when the session starts getting full.
Because we now[1] store info about each file upload separately in the
session the session isn’t overridden every time you upload a file. This
is good because you can do multiple file uploads idempotently.
Generally we are cleaning up after ourselves because we pop anything to
do with that upload from the session. However there is an edge case: if
you never send the file then the info about the file stays in the
session in perpetuity[2]. This is generally happening when people are
uploading files that are impossible to send, ie ones that have errors.
So this commit makes two changes:
1. remove info about a file upload from the session as soon as we know
that it contains errors
2. `POST` reuploads to the same endpoint as initial uploads because
otherwise we need to keep info about bad uploads in the session,
which would prevent us from doing 1.
1. https://github.com/alphagov/notifications-admin/pull/1968
2. or at least until the session is cleared by the user logging out
If you have a placeholder called `((phone number))` in your email
template, and you try to send a one-off message then the form input will
attempt to validate your ‘phone number’.
This is not helpful if you’re trying to put a landline number in your
email, for example.
This only affects messages being sent through the one-off interface.
This commit makes the form be aware of template type, which fixes the
problem.
we branch on any_ to either say "require ALL these permissions" or
"require ANY of these permissions". But we only ever call the decorator
with one permission, or with any_=True, so it's unnecessary
rather than allow admins to do everything specifically, we should
only block them from things we conciously don't want them to do.
This is "Don't let platform admins send letters from services they're
not in". Everything else the platform admins can do.
This is step one, adding a restrict_admin_usage flag, and setting that
for those restricted endpoints around creating api keys, uploading CSVs
and sending one-off messages.
Also, this commit separates the two use cases for permissions:
* user.has_permission for access control
* user.has_permission_for_service for user info - this is used for
showing checkboxes on the manage-users page for example
With this, we can remove the admin_override flag from the permission
decorator.
If someone has duplicate recipient columns in their file we don’t know
which one to use. This commit adds an error message which should help
them fix the duplication.
This commit doesn’t go to the extra effort to actually show the
correct values for duplication in the preview. Don’t think it’s worth
the effort/complexity for how infrequently we’ve seen this error.
Depends on:
- [ ] https://github.com/alphagov/notifications-utils/pull/376
Excel stores dates as floating point numbers, counting the days (or
fraction thereof) since 1900 (except when it counts from 1904).
However it also, incorrectly, recognises 1900 as a leap year. This means
that it’s ambiguous whether day 59 is February 28th, or February 27th,
depending if you’re counting up or down. In fact any number less than 60
is, therefore, ambiguous.
This shouldn’t really matter since no-one is going to be using dates in
the year 1900 in Notify messages. _Except_ when Excel misidentifies a
cell as containing a date. For example, if you have the number `9`
inside a cell, it means _house number 9_ if the next cell contains
_example_ street. but Excel is all like ‘oh they must want January 9th
1900!’ No. Bad Excel.
There’s not much we can do about this, but we can at least give people
an error message with the workaround, which is what this commit does.
Most of this commit message is paraphrased from:
http://xlrd.readthedocs.io/en/latest/dates.html
Done using isort[1], with the following command:
```
isort -rc ./app ./tests
```
Adds linting to the `run_tests.sh` script to stop badly-sorted imports
getting re-introduced.
Chosen style is ‘Vertical Hanging Indent’ with trailing commas, because
I think it gives the cleanest diffs, eg:
```
from third_party import (
lib1,
lib2,
lib3,
lib4,
)
```
1. https://pypi.python.org/pypi/isort
Spreadsheets start at row 1 (the header row), and the values don’t start
until row 2. The row numbers in our URLs start at 0, which is a concept
that only makes sense to programmers.
It’s more predictable and consistent to make the number in the URL match
the row number displayed on the page when previewing the spreadsheet.
We’ve heard from some users, especially those sending letters, that
they’d like to check that a spreadsheet they’ve uploaded has populated
the template correctly.
My reckon is that seeing just one row of the spreadsheet populate the
template isn’t enough to give people confidence that everything’s
working properly.
This commit adds links to all but the currently-previewed row. Clicking
that link will populate the preview with values from that row. These
pages already exist; they were created in this PR:
https://github.com/alphagov/notifications-admin/pull/1696
Because exceptions can be expensive performance wise (see:
https://docs.python.org/3/faq/design.html#how-fast-are-exceptions).
Since we’re counting the number of rows anyway this doesn’t introduce
any performance overhead there. And I think it’s equally readable/same
number of lines of code.
We’ve heard from some users, especially those sending letters, that
they’d like to check that a spreadsheet they’ve uploaded has populated
the template correctly.
My reckon is that seeing just one row of the spreadsheet populate the
template isn’t enough to give people confidence that everything’s
working properly. So this commit is the first step towards being able
to preview an arbitrary row of a template, by extending the URL
structure to optionally accept a row number for pages or files (ie PNG)
that preview successfully uploaded spreadsheets.
What this commit doesn’t do is link to these pages; that will come as
part of a subsequent commit.
Since instances of `Recipients` are now iterable we can just look up the
first row by index, rather than having to hit the rows property as a
generator.
There is a chance that there won’t be a first row, if the file has 1 or
fewer columns. So we still need to handle a possible exception (albeit
it a different one to before).
This variable isn’t used by our Jinja templates. Presumably it was
from the time before instances of `Template` were responsible for
showing who the email/text message was being sent to.
Now that the page title for picking a sender/reply to has been improved,
I think these pages are also less clear than they could be.
This commit changes the page titles to (I hope) be clearer about what is
needed from the user on these pages.
Changing the `<h1>` in https://github.com/alphagov/notifications-admin/pull/1638
turned out to be quite confusing. The combination of the word
"recipient" and a selection of email addresses on the page was confusing.
This commit changes the page title to be much more explicit about what
is expected from the page, rather than what is consistent with the text
of the link that the user clicked.
Changing the `<h1>` in https://github.com/alphagov/notifications-admin/pull/1638
turned out to be quite confusing. The combination of the word
"recipient" and a selection of email addresses on the page was confusing.
This commit changes the page title to be much more explicit about what
is expected from the page, rather than what is consistent with the text
of the link that the user clicked.
We have a sort of principle that when clicking a link, the page you land
on should be titled the same as the link you clicked.
This also reduces unnecessary repetition between the page title and the
form label.
Make it clear that:
- In the case of text messages, it’s about who the message comes from
- In the case of emails, it’s about where the user will reply to