2017-06-12 17:21:25 +01:00
|
|
|
|
# -*- coding: utf-8 -*-
|
2019-06-18 18:00:36 +01:00
|
|
|
|
from datetime import datetime
|
2017-12-30 16:54:39 +00:00
|
|
|
|
|
2017-06-12 17:21:25 +01:00
|
|
|
|
from flask import (
|
2018-02-20 11:22:17 +00:00
|
|
|
|
Response,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
jsonify,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
render_template,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
request,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
stream_with_context,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
url_for,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
)
|
2018-03-01 15:38:42 +00:00
|
|
|
|
|
2017-06-12 17:21:25 +01:00
|
|
|
|
from app import (
|
2017-12-30 16:54:39 +00:00
|
|
|
|
current_service,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
format_date_numeric,
|
|
|
|
|
|
job_api_client,
|
|
|
|
|
|
notification_api_client,
|
|
|
|
|
|
)
|
2017-06-12 17:21:25 +01:00
|
|
|
|
from app.main import main
|
2018-09-06 10:41:59 +01:00
|
|
|
|
from app.notify_client.api_key_api_client import KEY_TYPE_TEST
|
2017-06-12 17:21:25 +01:00
|
|
|
|
from app.utils import (
|
2018-02-20 11:22:17 +00:00
|
|
|
|
DELIVERED_STATUSES,
|
|
|
|
|
|
FAILURE_STATUSES,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
get_help_argument,
|
2018-02-20 11:22:17 +00:00
|
|
|
|
parse_filter_args,
|
|
|
|
|
|
set_status_filters,
|
|
|
|
|
|
)
|
2021-06-09 15:15:35 +01:00
|
|
|
|
from app.utils.csv import generate_notifications_csv
|
|
|
|
|
|
from app.utils.templates import get_template
|
2021-06-09 13:19:05 +01:00
|
|
|
|
from app.utils.user import user_has_permissions
|
2017-06-12 17:21:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
2019-11-04 11:07:55 +00:00
|
|
|
|
@main.route("/services/<uuid:service_id>/notification/<uuid:notification_id>")
|
2018-06-12 16:17:20 +01:00
|
|
|
|
@user_has_permissions('view_activity', 'send_messages')
|
2017-06-12 17:21:25 +01:00
|
|
|
|
def view_notification(service_id, notification_id):
|
2017-07-13 13:28:11 +01:00
|
|
|
|
notification = notification_api_client.get_notification(service_id, str(notification_id))
|
2018-01-03 10:44:36 +00:00
|
|
|
|
notification['template'].update({'reply_to_text': notification['reply_to_text']})
|
|
|
|
|
|
|
2018-11-02 14:18:58 +00:00
|
|
|
|
personalisation = get_all_personalisation_from_notification(notification)
|
2019-10-30 11:28:38 +00:00
|
|
|
|
error_message = None
|
2018-03-08 17:10:34 +00:00
|
|
|
|
|
2017-06-24 17:12:45 +01:00
|
|
|
|
template = get_template(
|
|
|
|
|
|
notification['template'],
|
|
|
|
|
|
current_service,
|
|
|
|
|
|
show_recipient=True,
|
2017-06-24 17:29:28 +01:00
|
|
|
|
redact_missing_personalisation=True,
|
Show 'From' / 'Reply To' if set for notification
Previously when a service had multiple "reply to" entries setup for
email or SMS, we would show the one that was selected on all screens
[1][2] except the final one, where the notification is actually sent.
This fixes that, with the caveat that it will also show for services
with only one "reply to" entry (see notes below) - we will look at
making this consistent on the previous screens in the next commit.
Here's a bit more detail on how this works:
- If a service has multiple "reply to" entries, the journey to send a
one-off message starts with a screen to select the "sender_id", which
is otherwise "None" [3].
- The "sender_id" is subsequently resolved to an actual email / phone
number by calling an API [4] and plucking it out of the response JSON.
- The email / phone number then get rendered as part of the preview
template [5][6].
- Unfortunately the "sender_id" is removed from the session by the time
we get to the "view_notification" view [7].
- However, we can get back the equivalent text from the notification
JSON, which is set by the API when the notification is created [8],
give or take a bit of validation code [9][10].
- But the "reply_to_text" field is also set by the API when the service
only has one "reply to" entry, so it will show then as well.
We could add look at the number of "reply to" entries for the service,
in order to consistently only show it when there is more the one. But
it seems more useful to show it on previous screens, since it provides
more information than is currently show (esp. for emails).
[1]: https://github.com/alphagov/notifications-admin/blob/93226ec5d6dde489fae6e2e605aa2cfc04a8eff0/app/main/views/send.py#L441-L442
[2]: https://github.com/alphagov/notifications-admin/blob/93226ec5d6dde489fae6e2e605aa2cfc04a8eff0/app/main/views/send.py#L966-L967
[3]: https://github.com/alphagov/notifications-admin/blob/93226ec5d6dde489fae6e2e605aa2cfc04a8eff0/app/main/views/send.py#L247
[4]: https://github.com/alphagov/notifications-admin/blob/93226ec5d6dde489fae6e2e605aa2cfc04a8eff0/app/main/views/send.py#L1071-L1082
[5]: https://github.com/alphagov/notifications-admin/blob/93226ec5d6dde489fae6e2e605aa2cfc04a8eff0/app/templates/views/notifications/notification.html#L80
[6]: https://github.com/alphagov/notifications-utils/blob/master/notifications_utils/jinja_templates/sms_preview_template.jinja2
[7]: https://github.com/alphagov/notifications-admin/blob/93226ec5d6dde489fae6e2e605aa2cfc04a8eff0/app/main/views/send.py#L1059
[8]: https://github.com/alphagov/notifications-api/blob/f8b4c9151cd135195c2fe416d4f54516d8d3833f/app/service/send_notification.py#L87-L93
[9]: https://github.com/alphagov/notifications-api/blob/f8b4c9151cd135195c2fe416d4f54516d8d3833f/app/models.py#L653
[10]: https://github.com/alphagov/notifications-utils/blob/master/notifications_utils/recipients.py#L482
2021-02-08 16:38:50 +00:00
|
|
|
|
sms_sender=notification['reply_to_text'],
|
|
|
|
|
|
email_reply_to=notification['reply_to_text'],
|
2017-06-24 17:12:45 +01:00
|
|
|
|
)
|
2018-11-02 14:18:58 +00:00
|
|
|
|
template.values = personalisation
|
2017-06-24 17:12:45 +01:00
|
|
|
|
if notification['job']:
|
|
|
|
|
|
job = job_api_client.get_job(service_id, notification['job']['id'])['data']
|
|
|
|
|
|
else:
|
|
|
|
|
|
job = None
|
2017-07-13 13:05:41 +01:00
|
|
|
|
|
2019-06-07 16:16:13 +01:00
|
|
|
|
if get_help_argument() or request.args.get('help') == '0':
|
|
|
|
|
|
# help=0 is set when you’ve just sent a notification. We
|
|
|
|
|
|
# only want to show the back link when you’ve navigated to a
|
|
|
|
|
|
# notification, not when you’ve just sent it.
|
|
|
|
|
|
back_link = None
|
2019-05-09 17:33:22 +01:00
|
|
|
|
elif request.args.get('from_job'):
|
|
|
|
|
|
back_link = url_for(
|
|
|
|
|
|
'main.view_job',
|
|
|
|
|
|
service_id=current_service.id,
|
|
|
|
|
|
job_id=request.args.get('from_job'),
|
|
|
|
|
|
)
|
|
|
|
|
|
else:
|
|
|
|
|
|
back_link = url_for(
|
|
|
|
|
|
'main.view_notifications',
|
|
|
|
|
|
service_id=current_service.id,
|
|
|
|
|
|
message_type=template.template_type,
|
2019-05-15 10:04:43 +01:00
|
|
|
|
status='sending,delivered,failed',
|
2019-05-09 17:33:22 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
2017-06-12 17:21:25 +01:00
|
|
|
|
return render_template(
|
|
|
|
|
|
'views/notifications/notification.html',
|
|
|
|
|
|
finished=(notification['status'] in (DELIVERED_STATUSES + FAILURE_STATUSES)),
|
2018-10-11 10:54:39 +01:00
|
|
|
|
notification_status=notification['status'],
|
2019-10-30 11:28:38 +00:00
|
|
|
|
message=error_message,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
uploaded_file_name='Report',
|
2017-06-24 17:12:45 +01:00
|
|
|
|
template=template,
|
|
|
|
|
|
job=job,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
updates_url=url_for(
|
|
|
|
|
|
".view_notification_updates",
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
notification_id=notification['id'],
|
|
|
|
|
|
status=request.args.get('status'),
|
|
|
|
|
|
help=get_help_argument()
|
|
|
|
|
|
),
|
|
|
|
|
|
partials=get_single_notification_partials(notification),
|
2017-06-24 17:12:45 +01:00
|
|
|
|
created_by=notification.get('created_by'),
|
|
|
|
|
|
created_at=notification['created_at'],
|
2018-10-11 10:54:39 +01:00
|
|
|
|
updated_at=notification['updated_at'],
|
2017-07-13 13:05:41 +01:00
|
|
|
|
help=get_help_argument(),
|
2017-10-16 10:30:59 +01:00
|
|
|
|
notification_id=notification['id'],
|
2018-07-20 08:43:02 +01:00
|
|
|
|
can_receive_inbound=(current_service.has_permission('inbound_sms')),
|
2019-01-17 14:22:58 +00:00
|
|
|
|
sent_with_test_key=(
|
|
|
|
|
|
notification.get('key_type') == KEY_TYPE_TEST
|
|
|
|
|
|
),
|
2019-05-09 17:33:22 +01:00
|
|
|
|
back_link=back_link,
|
2017-06-12 17:21:25 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-11-04 11:07:55 +00:00
|
|
|
|
@main.route("/services/<uuid:service_id>/notification/<uuid:notification_id>.json")
|
2018-06-12 16:17:20 +01:00
|
|
|
|
@user_has_permissions('view_activity', 'send_messages')
|
2017-06-12 17:21:25 +01:00
|
|
|
|
def view_notification_updates(service_id, notification_id):
|
|
|
|
|
|
return jsonify(**get_single_notification_partials(
|
|
|
|
|
|
notification_api_client.get_notification(service_id, notification_id)
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_single_notification_partials(notification):
|
|
|
|
|
|
return {
|
|
|
|
|
|
'status': render_template(
|
|
|
|
|
|
'partials/notifications/status.html',
|
2018-09-06 10:41:59 +01:00
|
|
|
|
notification=notification,
|
|
|
|
|
|
sent_with_test_key=(
|
|
|
|
|
|
notification.get('key_type') == KEY_TYPE_TEST
|
|
|
|
|
|
),
|
2017-06-12 17:21:25 +01:00
|
|
|
|
),
|
|
|
|
|
|
}
|
2017-06-24 17:12:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_all_personalisation_from_notification(notification):
|
2017-06-24 17:29:28 +01:00
|
|
|
|
|
|
|
|
|
|
if notification['template'].get('redact_personalisation'):
|
|
|
|
|
|
notification['personalisation'] = {}
|
|
|
|
|
|
|
2017-06-24 17:12:45 +01:00
|
|
|
|
if notification['template']['template_type'] == 'email':
|
2017-06-30 15:18:03 +01:00
|
|
|
|
notification['personalisation']['email_address'] = notification['to']
|
2017-06-24 17:29:28 +01:00
|
|
|
|
|
2017-06-24 17:12:45 +01:00
|
|
|
|
if notification['template']['template_type'] == 'sms':
|
2017-06-30 15:18:03 +01:00
|
|
|
|
notification['personalisation']['phone_number'] = notification['to']
|
2017-06-24 17:29:28 +01:00
|
|
|
|
|
2017-06-30 15:18:03 +01:00
|
|
|
|
return notification['personalisation']
|
2017-12-30 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
2019-11-04 11:07:55 +00:00
|
|
|
|
@main.route("/services/<uuid:service_id>/download-notifications.csv")
|
2018-03-01 10:30:17 +00:00
|
|
|
|
@user_has_permissions('view_activity')
|
2017-12-30 16:54:39 +00:00
|
|
|
|
def download_notifications_csv(service_id):
|
|
|
|
|
|
filter_args = parse_filter_args(request.args)
|
|
|
|
|
|
filter_args['status'] = set_status_filters(filter_args)
|
|
|
|
|
|
|
2018-12-03 17:57:11 +00:00
|
|
|
|
service_data_retention_days = current_service.get_days_of_retention(filter_args.get('message_type')[0])
|
2017-12-30 16:54:39 +00:00
|
|
|
|
return Response(
|
|
|
|
|
|
stream_with_context(
|
|
|
|
|
|
generate_notifications_csv(
|
|
|
|
|
|
service_id=service_id,
|
|
|
|
|
|
job_id=None,
|
|
|
|
|
|
status=filter_args.get('status'),
|
|
|
|
|
|
page=request.args.get('page', 1),
|
2018-07-02 15:48:00 +01:00
|
|
|
|
page_size=10000,
|
2018-01-15 12:29:03 +00:00
|
|
|
|
format_for_csv=True,
|
2018-06-25 16:29:40 +01:00
|
|
|
|
template_type=filter_args.get('message_type'),
|
2018-09-27 14:51:36 +01:00
|
|
|
|
limit_days=service_data_retention_days,
|
2017-12-30 16:54:39 +00:00
|
|
|
|
)
|
|
|
|
|
|
),
|
|
|
|
|
|
mimetype='text/csv',
|
|
|
|
|
|
headers={
|
|
|
|
|
|
'Content-Disposition': 'inline; filename="{} - {} - {} report.csv"'.format(
|
|
|
|
|
|
format_date_numeric(datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ")),
|
|
|
|
|
|
filter_args['message_type'][0],
|
2018-07-20 08:42:01 +01:00
|
|
|
|
current_service.name)
|
2017-12-30 16:54:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
)
|