Commit Graph

3924 Commits

Author SHA1 Message Date
Rebecca Law
590f29b28a SQLAlchemy 1.4 requires SQLALCHEMY_DATABASE_URI to use postgresql rather than postgres for the connection uri to the database.
When deploying to paas the database postgres environment variables are set using VCAP_SERVICES provided by PaaS. When we start up the app and set the properties we need to replace the postgres string with postgresql for the app to start up properly.
This wasn't caught locally or with the unit tests because we were setting this property with postgresql.
2021-04-29 13:49:37 +01:00
Rebecca Law
424796bdcc Add unit test for archiving a template with a template folder 2021-04-29 13:32:36 +01:00
Rebecca Law
68d28aa83b The update of SQLAlchemy 1.4.10 has caused some conflicts in our code. This PR fixes most of those conflicts.
- sqlalchemy.sql.expression.case must include an else statement.
- clearly define list of columns for inbound_sms_history insert, getting the list from InboundSmsHistory.__table__.c was causing data type errors.
- remove relationships when not needed, the foreign key relationship is established in the creation of the column. This will get rid of the warnings referenced here: http://sqlalche.me/e/14/qzyx.
- update queries now that he user relationship in ServiceUser db model has been removed.
- move the check that a template is archived to the view instead of the dao method. The check was clearing the session before the version history could be done.

Deleting notifications in the night tasks still needs to be
investigated. The raw sql is causing an error.
2021-04-29 13:32:36 +01:00
Pea Tyczynska
df19a91b7f Update error messages after SQLAlchemy version update 2021-04-29 13:32:36 +01:00
Ben Thorner
23f4ae32df Merge pull request #3214 from alphagov/check-broadcast-suspended
Enforce service suspension for broadcasts
2021-04-28 15:01:11 +01:00
Rebecca Law
85895a9e8b Revert "Scheduled weekly dependency update for week 16" 2021-04-28 10:17:16 +01:00
Rebecca Law
10b0554784 Merge pull request #3219 from alphagov/pyup-scheduled-update-2021-04-21
Scheduled weekly dependency update for week 16
2021-04-28 09:20:35 +01:00
Rebecca Law
dcd08a0e45 Add unit test for archiving a template with a template folder 2021-04-27 12:30:50 +01:00
Ben Thorner
99bc29418e Move request_id injection into send_task override
This applies the same change we made in other apps [1][2]. Adding
the override here is special, though, because it means the others
will now get triggered, since this app is the start of the chain
of tasks for a request. We will also retain existing request_id
tracing for tasks within this app, since "apply_async" calls the
"send_task" method internally, which is the one we're overriding.

[1]: 6f3c118a1e
[2]: 2e08b7aa95
2021-04-27 10:35:21 +01:00
Rebecca Law
5f26d16915 Merge pull request #3218 from alphagov/precomplied-letter-transation
Introduce transaction for precompiled letters
2021-04-26 13:10:31 +01:00
Rebecca Law
1b070d69a1 The update of SQLAlchemy 1.4.10 has caused some conflicts in our code. This PR fixes most of those conflicts.
- sqlalchemy.sql.expression.case must include an else statement.
- clearly define list of columns for inbound_sms_history insert, getting the list from InboundSmsHistory.__table__.c was causing data type errors.
- remove relationships when not needed, the foreign key relationship is established in the creation of the column. This will get rid of the warnings referenced here: http://sqlalche.me/e/14/qzyx.
- update queries now that he user relationship in ServiceUser db model has been removed.
- move the check that a template is archived to the view instead of the dao method. The check was clearing the session before the version history could be done.

Deleting notifications in the night tasks still needs to be
investigated. The raw sql is causing an error.
2021-04-26 11:50:30 +01:00
Pea Tyczynska
e1a626855d Update error messages after SQLAlchemy version update 2021-04-23 16:48:36 +01:00
Chris Hill-Scott
f8bca5765d Validate length of broadcast templates on creation
This is a belt-and-braces check because the admin app already checks
this. But since we do it for SMS already it makes sense to replicate it
for broadcast templates.
2021-04-22 17:11:31 +01:00
Chris Hill-Scott
7c6ae40034 Normalise broadcast content before validating length
This changes the content length validation of the internal API to match
the validation of the public broadcast API[1].

This removes the length check from JSONSchema, which isn’t sophisticated
enough to deal with things like normalising newlines or handling
different encodings.

The admin app should catch these errors before they’re raised here, but
it’s best to be belt and braces.

1.7ab0403ae7/app/v2/broadcast/post_broadcast.py (L53-L63)
2021-04-22 14:42:54 +01:00
Rebecca Law
cb8ec9a4f7 Wrap the saving the notification and uploading the precompiled letter to
s3 in a transation.

If the upload to s3 fails the notification will not be saved to the
database.
2021-04-22 13:39:41 +01:00
Rebecca Law
fbd231cefd Merge pull request #3179 from alphagov/add-international-firetext-api-key
Add international API key for firetext
2021-04-21 08:49:11 +01:00
Pea Tyczynska
38af26cc78 Merge pull request #3199 from alphagov/admin-cancel-broadcast
Allow platform admins to cancel broadcasts.
2021-04-20 14:47:45 +01:00
Rebecca Law
f3fdd3b09b Add internation api key for firetext.
We want to start using Firetext for sending international SMS. They
require us to use a different API key for international SMS because it
requires a new code path to switch the sender ID to something that the
country will accept.
This PR does not include switching the sender of international SMS to
Firetext but sets us up to do so.
2021-04-20 13:58:55 +01:00
Pea Tyczynska
fce6a2d8dc Allow platform admins to cancel broadcasts.
Also update error message for when someone does not have permissions.

The message referenced approving broadcasts specifically, whereas
people would also see it if they try to cancel or reject
broadcast without permission.

Why we allow platform admins to cancel broadcasts:
we do this so they can react quickly if a broadcast was
approved by accident.
2021-04-20 12:27:38 +01:00
Ben Thorner
0507e8d9ad Raise 403 when broadcasting on a suspended service
This mirrors the approach we take for jobs [1].

[1]: 3d71815956/app/job/rest.py (L146)
2021-04-19 17:13:16 +01:00
Ben Thorner
a2af8b052a Split up authorisation vs. sequencing checks
While both of these are integrity errors (since we should never
reach this point in the code + data), this just means the original
method comment is still relevant to what immediately follows it.
2021-04-19 17:13:15 +01:00
Ben Thorner
936c9ebdfe Test sanity checks by calling top-level task
Since the checks are only performed in one place we can easily take
extra care to ensure this in the tests, noting that we don't need to
do any additional setup, except if no exception is raised - I've left
these tests as-is, to avoid doing more setup.

Note that we still check the happy path for when a provider message is
already sending - just in a different test [1].

[1]: 3d71815956/tests/app/celery/test_broadcast_message_tasks.py (L263)
2021-04-19 17:13:14 +01:00
Ben Thorner
ee52e3e2c9 Mirror integrity checks from the API
It makes sense to have these checks [1] here, since in future we may
add other ways of creating a broadcast event and omit them.

[1]: 3d71815956/app/broadcast_message/rest.py (L198)
2021-04-19 17:13:13 +01:00
Ben Thorner
0070473f31 Check for suspension before sending a broadcast
This mirrors the check we do for jobs, which are also a high-impact
task [1]. While this shouldn't be possible, just like other checks
we're adding it here to be doubly certain.

[1]: 3d71815956/app/celery/tasks.py (L74)
2021-04-19 17:13:12 +01:00
Ben Thorner
b2398fcaf4 Rename CBCProxyFatalException
We only actually use this when the data we're working with is in an
unexpected state, which is unrelated to the CBC Proxy. Using this
name also means we can re-use this exception in the next commits.

Note that we may still care if a broadcast message has expired, since
it's not expected that someone would send one in this condition.
2021-04-19 17:13:05 +01:00
Rebecca Law
ae57521b39 Simplify the get_free_sms_fragment limit for the case when the row is
missing, by setting the free allowance to the default.
2021-04-19 13:29:04 +01:00
Rebecca Law
bcd1939179 Merge pull request #3212 from alphagov/update-zendesk-message
Update the Zendesk ticket content for `check_if_letters_still_in_created`
2021-04-19 11:36:28 +01:00
Rebecca Law
91542ad33e Merge pull request #3197 from alphagov/update-annual-billing-if-org-changes
Set default free allow when organisation for a service changes
2021-04-19 11:34:24 +01:00
Rebecca Law
d4009ffc52 Rename database management functions.
Rename @transactional to @autocommit.
Rename nested_transaction to tranaction.
2021-04-19 10:56:00 +01:00
Rebecca Law
34a378a60e Update the Zendesk ticket content for
`check_if_letters_still_in_created`

The message to Zendesk includes a list of notification ids, this isn't
really necessary and is included in the run book. Creation of the
Zendesk ticket can fail if the message is too long, removing the list of
ids can prevent that from happening.
2021-04-19 10:47:25 +01:00
Katie Smith
e737217c3f Merge pull request #3208 from alphagov/check-bcast-service-live
Check if service is in live mode before sending a broadcast
2021-04-16 09:11:53 +01:00
Ben Thorner
be02573147 Fix apply_async not working with positional kwargs
Celery's apply_async function accepts 'kwargs' as (get ready to be
confused) either a positional argument, or a keyword argument:

Positional: apply_async(['args'], {'kw': 'args'})

Keyword: apply_async(args=['args'], kwargs={'kw': 'args'})

We rely on the positional form in at least one place [1]. This fixes
the overload of apply_async to cope with both forms, and continue to
pass through any other (confusion time again) keyword args to super(),
such as queue="queue".

Note that we've also decided to stop accepting other positional args,
since this is unnecessarily confusing, and we don't currently rely on
it in our code. This stops it creeping in in future.

[1]: fde927e00e/app/job/rest.py (L186)
2021-04-15 17:21:21 +01:00
Katie Smith
59978fd99a Check if a service is live before sending a broadcast
We only want to send a broadcast if the broadcast message is not stubbed
and the service is live at the point at which the broadcast event should
be created. This is to prevent the situation where a broadcast service is
switched to live / trial mode in between the message being created and
approved (we log an error if this happens).

A stubbed broadcast message with a trial mode service at the point of
approval is not an issue - trial mode services can approve their own
broadcasts. In this situation, we don't create the broadcast event but
also don't need to log an error.
2021-04-15 15:01:32 +01:00
Katie Smith
df82b514d1 Don't create broadcast event unless necessary
If we're not going to send a broadcast, we don't need to create the
BroadcastEvent in the database. The BroadcastMessage contains all the
data we need - the BroadcastEvent is not used.

Not creating the event when we won't send the broadcast (e.g. when the
broadcast message was created when the service was in trial mode) adds
an extra layer of security.
2021-04-15 14:55:45 +01:00
Rebecca Law
93908bacda New strategy for transaction management.
Introduce a contextmanger function to handle exceptions and nested
transactions. Using the nested_transaction will start a
nested transaction with `db.session.begin_nested`, once the nested
transaction is complete the commit will happen.
`@transactional` has been updated to commit unless in a nested
transaction.
2021-04-14 07:04:17 +01:00
Rebecca Law
cf35135605 Adding @nested_transactional for transactions that require more than one
db update/insert.

Using a savepoint for the multiple transactions allows us to rollback if
there is an error when executing the second db transaction.
However, this does add a bit of complexity. Developers need to manage
the db session when calling multiple nested tranactions.

Unit tests have been added to test this functionality and some end to
end tests have been done to make sure all transactions are rollback if
there is an exception while executing the transaction.
2021-04-14 07:03:57 +01:00
Rebecca Law
9a03e579d6 When a service is created add the default annual billing for the service.
This will need to be merged before https://github.com/alphagov/notifications-admin/pull/3855, it will be that until the admin PR is merged the annual billing will be set twice, but that's not an issue.
2021-04-14 07:03:57 +01:00
Rebecca Law
69e5ddae4f When a service is associated with a organisation set the free allowance to
the default free allowance for the organisation type.

The update/insert for the default free allowance is done in a separate
transaction. Updates to services need to happen in a transaction to
trigger the insert into the ServicesHistory table. For that reason the
call to set_default_free_allowance_for_service is done after the service
is updated.
I've added a try/except around the set_default_free_allowance_for_service call to ensure we still get the update to the service but get an exception log if the update to annual_billing fails. I believe it's important to preserve the update to the service in the unlikely event that the annual_billing upsert fails.
2021-04-14 07:03:57 +01:00
Ben Thorner
ec6d87cd0f Simplify argument passing in apply_async
This avoids the need to keep in-sync with any future changes to the
signature, and reduces the amount of irrelevant code to read.
2021-04-13 15:12:45 +01:00
David McDonald
2e6d761691 Merge pull request #3204 from alphagov/broadcast-envars
Broadcast envars
2021-04-12 17:25:15 +01:00
David McDonald
295162c81d Move CBC proxy enable check
This change will make our development environments closer to production
even if they aren't hooked up to the CBC proxy lambda functions.

Now in development, we will create the broadcast event and create tasks
for each broadcast provider event. We will still not create actual
broadcast provider message rows in the DB and talk to the CBC proxies.

This should be helpful in development to catch any issues we introduce
to do with sending broadcast messaging. In time we may wish to have some
fake CBC proxies in the AWS tools account that we can interact with to
make it even more realistic.
2021-04-12 17:05:41 +01:00
Ben Thorner
3e507eea55 Merge pull request #3201 from alphagov/revamp-celery-stats
Migrate towards new metrics for Celery tasks
2021-04-12 15:04:37 +01:00
Ben Thorner
37f91e0214 Add tests for apply_async injecting request_id 2021-04-12 14:50:55 +01:00
Ben Thorner
df6e27d8fd Add test for extracting request_id in __call__
Tasks will fail if we leave the kwarg in, so I think it's quite
important that we test this works. We don't cover this in any other
test because we call the task functions directly, so the request_id
kwarg doesn't get injected beforehand.
2021-04-12 14:50:53 +01:00
Ben Thorner
8954cec5a1 Add tests for celery task superclass
This requires upgrading freezegun, as time.monotonic wasn't frozen
by v1.0. Note that we need to explicitly specify the base class for
the task in the test, the reason for which is quite subtle:

- Normally, by using the 'notify_api' fixture, the base class is set
to NotifyTask automatically by running app.create_app [1].

- However, when run alongside other tests, the imports of files with
other celery tasks cause the base class to be instantiated and cached
as the default Celery one. This means none of our tests actually use
our custom superclass when testing tasks.

Because we can't run 'apply_async' directly (since this would require
an actual Celery broker), we need to manually push/pop the request
Context that's normally done as part of sending a task.

Note also that we use a UUID as the name for a task, since these are
global. We want to avoid the task polluting other tests in future,
as well as make it clear the task is being reused.

[1]: dea5828d0e/app/__init__.py (L113)
2021-04-12 14:50:02 +01:00
Leo Hemsted
4a5b1c23bd only send zendesk P1 for alerts
we don't need to be re-notified when someone clicks cancel
2021-04-08 12:22:18 +01:00
Leo Hemsted
9bd8c0239c look for 'live', not 'production'
config['NOTIFY_ENVIRONMENT'] is hardcoded to `'live'` in the Live config
class. The values as seen on the environment which we send real messages
from:

```
>>> json.loads(os.environ['VCAP_APPLICATION'])['space_name']  # what cloudfoundry sets
'production'
>>> os.environ['NOTIFY_ENVIRONMENT']  # we set this from cloudfoundry
'production'
>>> current_app.config['NOTIFY_ENVIRONMENT']  # hardcoded in the Live config
'live'
>>> current_app.config['NOTIFICATION_QUEUE_PREFIX']  # pulled from env var of same name
'live'
>>> current_app.config['ENV']  # this is an unrelated flask variable
'production'
```
2021-04-08 12:17:22 +01:00
Leo Hemsted
df393e36c5 send a p1 when a broadcast goes out on production
it's important to keep tabs on when these things leave our system.
Sending a zendesk ticket that triggers a P1 is probably our simplest way
of notifying the team when this happens (it's what we do with out of
hours emergencies on the admin app too). We don't have any direct
pagerduty integrations from the api app, but we already have the zendesk
client hooked up.

After broadcasts go live, we may want to change this to a P2 (but even
then, there's arguments for keeping it P1 to start with I think).

Don't cause a P1 if it goes out on staging as that might be MNOs testing.
2021-04-06 11:32:19 +01:00
Rebecca Law
220047628b Merge pull request #3193 from alphagov/populate-annual-billing-2021
Populate annual billing for 2021
2021-03-31 07:58:16 +01:00
Rebecca Law
da8a7a8db1 Avoid key errors by setting the year_start with 2020 or 2021
Remove db.create_service_with_organisation method
Update comment in command
2021-03-30 09:08:04 +01:00