new endpoints:
/services/<service_id>/move-to-folder
/services/<service_id>/move-to-folder/<target_template_folder_id>
* takes in a dict containing lists of `templates` and `folders` uuids.
* sets parent of templates and folders to the folder specified in the
URL. Or None, if there was no id specified.
* if any template or folder has a differen service id, then the whole
update fails
* if any folder is an ancestor of the target folder, then the whole
update fails (as that would cause a cyclical folder structure).
* the whole function is wrapped in a single `transactional` decorator,
so in case of error nothing will be saved.
The `serialize` method of the Notification model now includes the
`created_by_name`. If a notification was sent as a one-off message this
value will now be the name of the person who sent the notification. If
a notification was sent through the API or by a CSV upload we don't
record the id of the sender, so `created_by_name` will be `None`.
This change affects the data that gets returned from these endpoints:
* /v2/notifications/<notification_id>
* /v2/notifications
Postcodes are required for created letters, but not for precompiled, this fix allows postcodes to be None in the model.
As postcodes are still required for created letter they should be caught by validation schemas in the POST handler
The personalisation for letters can take different formats depending on
how the letter was generated, for example it can contain either
address_line_1 or addressline1. This change ensures that it is always
serialized in the same way.
Adds test for:
* checking the template version foreign key constraint
* checking that template changes don't affect existing notifications
* notification statistics aren't affected by different template versions
* notification stats always return the current template name
`Notification.template` changed from being a Template relationship
to TemplateHistory. When a relationship attribute is being assigned,
SQLAlchemy checks that the assigned value type matches the relationship
type. Since most tests at the moment create a notification using a
Template instance this check fails.
Rewriting the tests to use TemplateHistory objects would require
changes to the majority of tests. Instead, when creating a notification
objects we assign the foreign key attributes directly. This skips the
SQLAlchemy type check, but we still get the constraint check on the
foreign keys, so a matching TemplateHistory object needs to exist in
the database.
Refactor tests/db/create_service() to behave more like the real world.
Created new create_service_with_inbound_number and create_service_with_defined_sms_sender() test/db methods.
created and sending aren't quite as helpful for letters, since their
journey through notify and our providers is so different to emails/sms.
So instead, we should return estimated_dispatch_date (in a future PR)
and the status should just read received_by_notify
There are a variety of ways a notification can be created - via the
API, via CSV, via one-off messages, via the same but sent as a test -
the point is, there are lots of entry points, and lots of inconsistency
about how personalisation may be sent in. If there are no
personalisation options in the template, we may get either `None` or
`{}` - if the value is None, to avoid an error in our encryption lib,
we just store None in the database.
THIS ENDS NOW!
We've had some problems on the front-end that is caused by
notifications having the `None` value. This commit changes the
personalisation property getter and setter to store/return `{}`
rather than None.
"sent" is fine as an internal marker but not very obvious to the end
user that it specifically refers to international messages. We now
say "Sent internationally" in the CSV
* Introduces separate method on Notification to serialise the notification
* ready for csv output
* Fixes issue where job_row_number = 0 not being accounted for correctly
There are no more notifications whose statuses are "failed", as
the "failed" status has now been replaced with statuses that are
more specific about the nature of the failure.
However, we still want to be able to filter by failing
notifications. (ie "/v2/notifications?status=failed").
Created a `.substitute_status()` method which takes a status
string or list of status strings and, if it finds 'failure',
replaces it with the other failing status types.
This way, calling for nottifications with "?status=failed" is
internally treated as
"status = ['technical-failure', 'temporary-failure', 'permanent-failure']"
The "cost" value was flawed for a couple of reasons.
1. Lots of messages are free, so in those instances the "cost"
doesn't tell you anything
2. The query to get the rate was expensive and we don't have
an obvious way to get it back very efficiently for large numbers
of notifications.
So we scrapped it.
In the V2 API, the GET response for an individual notification
returns a 'cost' value, which we can get by multiplying the
billable units by the per-message rate of the supplier who
sent the message.
Any notifications with billable units > 0 but without a
corresponding `ProviderRates` entry will blow up the application,
so make sure you've got one.
This is used to construct a notification from the sorts of data an API call provides. This is used in both the db-email / db-sms tasks and the notifications rest endpoint to construct the notification DB object.