Files
notifications-admin/app/main/views/notifications.py
Katie Smith 088d6ee4b0 Content changes for notification pages
This commit adds content pages for the notifications pages, particularly
the letter pages, which will make things clearer now that we will soon be allowing
letters to be cancelled.

The main changes are:
* The confirmation banner for letters sent from a CSV file now states when
printing will start.
* We state the CSV file that notifications were sent from on the
notifications page
* The notification page for letters shows when printing starts (today,
tomorrow, or that date that the letter was printed)
2018-12-03 10:42:47 +00:00

225 lines
7.5 KiB
Python

# -*- coding: utf-8 -*-
import base64
import io
import os
from datetime import datetime, timedelta
from dateutil import parser
from flask import (
Response,
abort,
current_app,
jsonify,
render_template,
request,
stream_with_context,
url_for,
)
from flask_login import login_required
from notifications_python_client.errors import APIError
from notifications_utils.letter_timings import (
get_letter_timings,
letter_can_be_cancelled,
)
from notifications_utils.pdf import pdf_page_count
from notifications_utils.timezones import utc_string_to_aware_gmt_datetime
from app import (
_format_datetime_short,
current_service,
format_date_numeric,
job_api_client,
notification_api_client,
service_api_client,
)
from app.main import main
from app.notify_client.api_key_api_client import KEY_TYPE_TEST
from app.template_previews import get_page_count_for_letter
from app.utils import (
DELIVERED_STATUSES,
FAILURE_STATUSES,
generate_notifications_csv,
get_help_argument,
get_template,
parse_filter_args,
printing_today_or_tomorrow,
set_status_filters,
user_has_permissions,
)
@main.route("/services/<service_id>/notification/<uuid:notification_id>")
@login_required
@user_has_permissions('view_activity', 'send_messages')
def view_notification(service_id, notification_id):
notification = notification_api_client.get_notification(service_id, str(notification_id))
notification['template'].update({'reply_to_text': notification['reply_to_text']})
personalisation = get_all_personalisation_from_notification(notification)
if notification['template']['is_precompiled_letter']:
file_contents = view_letter_notification_as_preview(service_id, notification_id, "pdf")
page_count = pdf_page_count(io.BytesIO(file_contents))
else:
page_count = get_page_count_for_letter(notification['template'], values=personalisation)
template = get_template(
notification['template'],
current_service,
letter_preview_url=url_for(
'.view_letter_notification_as_preview',
service_id=service_id,
notification_id=notification_id,
filetype='png',
),
expand_emails=True,
page_count=page_count,
show_recipient=True,
redact_missing_personalisation=True,
)
template.values = personalisation
if notification['job']:
job = job_api_client.get_job(service_id, notification['job']['id'])['data']
else:
job = None
letter_print_day = get_letter_printing_statement(notification['status'], notification['created_at'])
return render_template(
'views/notifications/notification.html',
finished=(notification['status'] in (DELIVERED_STATUSES + FAILURE_STATUSES)),
notification_status=notification['status'],
uploaded_file_name='Report',
template=template,
job=job,
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),
created_by=notification.get('created_by'),
created_at=notification['created_at'],
updated_at=notification['updated_at'],
help=get_help_argument(),
estimated_letter_delivery_date=get_letter_timings(
notification['created_at'],
postage=notification['postage']
).earliest_delivery,
notification_id=notification['id'],
postage=notification['postage'],
can_receive_inbound=(current_service.has_permission('inbound_sms')),
is_precompiled_letter=notification['template']['is_precompiled_letter'],
letter_print_day=letter_print_day
)
def get_letter_printing_statement(status, created_at):
created_at_dt = parser.parse(created_at).replace(tzinfo=None)
if letter_can_be_cancelled(status, created_at_dt):
return 'Printing starts {} at 5.30pm'.format(printing_today_or_tomorrow())
else:
printed_datetime = utc_string_to_aware_gmt_datetime(created_at) + timedelta(hours=6, minutes=30)
printed_date = _format_datetime_short(printed_datetime)
return 'Printed on {}'.format(printed_date)
def get_preview_error_image():
path = os.path.join(os.path.dirname(__file__), "..", "..", "static", "images", "preview_error.png")
with open(path, "rb") as file:
return file.read()
@main.route("/services/<service_id>/notification/<uuid:notification_id>.<filetype>")
@login_required
@user_has_permissions('view_activity')
def view_letter_notification_as_preview(service_id, notification_id, filetype):
if filetype not in ('pdf', 'png'):
abort(404)
try:
preview = notification_api_client.get_notification_letter_preview(
service_id,
notification_id,
filetype,
page=request.args.get('page')
)
display_file = base64.b64decode(preview['content'])
except APIError:
display_file = get_preview_error_image()
return display_file
@main.route("/services/<service_id>/notification/<notification_id>.json")
@user_has_permissions('view_activity', 'send_messages')
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',
notification=notification,
sent_with_test_key=(
notification.get('key_type') == KEY_TYPE_TEST
),
),
}
def get_all_personalisation_from_notification(notification):
if notification['template'].get('redact_personalisation'):
notification['personalisation'] = {}
if notification['template']['template_type'] == 'email':
notification['personalisation']['email_address'] = notification['to']
if notification['template']['template_type'] == 'sms':
notification['personalisation']['phone_number'] = notification['to']
return notification['personalisation']
@main.route("/services/<service_id>/download-notifications.csv")
@login_required
@user_has_permissions('view_activity')
def download_notifications_csv(service_id):
filter_args = parse_filter_args(request.args)
filter_args['status'] = set_status_filters(filter_args)
service_data_retention_days = service_api_client.get_service_data_retention_by_notification_type(
service_id, filter_args.get('message_type')[0]
).get('days_of_retention', current_app.config['ACTIVITY_STATS_LIMIT_DAYS'])
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),
page_size=10000,
format_for_csv=True,
template_type=filter_args.get('message_type'),
limit_days=service_data_retention_days,
)
),
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],
current_service.name)
}
)