Files
notifications-api/app/notifications/rest.py
Leo Hemsted 25d1777937 ensure we're passing through api keys and key types from notifications
when we made the change to async persist notifications, we forgot to
pass through api_key_id and key_type. in send_sms/email, for legacy
reasons, they default to None/KEY_TYPE_NORMAL, so regardless of what
your api key was set up as, we would send real messages!

TODO: Once the PaaS transition is complete and the task changes are
reverted, remove the api_key_id and key_type params from the send_*
tasks entirely, as those are only called from the csv job flow, and
don't need them
2017-03-28 13:14:46 +01:00

220 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import (
Blueprint,
jsonify,
request,
current_app,
json
)
from app import api_user, encryption, create_uuid
from app.celery import tasks
from app.dao import (
templates_dao,
services_dao,
notifications_dao
)
from app.models import KEY_TYPE_TEAM, PRIORITY, KEY_TYPE_TEST
from app.models import SMS_TYPE
from app.notifications.process_client_response import (
validate_callback_data,
process_sms_client_response
)
from app.notifications.process_notifications import (persist_notification,
send_notification_to_queue,
simulated_recipient)
from app.notifications.validators import (check_service_message_limit,
check_template_is_for_notification_type,
check_template_is_active)
from app.schemas import (
email_notification_schema,
sms_template_notification_schema,
notification_with_personalisation_schema,
notifications_filter_schema,
notifications_statistics_schema,
day_schema
)
from app.service.utils import service_allowed_to_send_to
from app.utils import pagination_links, get_template_instance
notifications = Blueprint('notifications', __name__)
from app.errors import (
register_errors,
InvalidRequest
)
register_errors(notifications)
@notifications.route('/notifications/<uuid:notification_id>', methods=['GET'])
def get_notification_by_id(notification_id):
notification = notifications_dao.get_notification_with_personalisation(str(api_user.service_id),
notification_id,
key_type=None)
return jsonify(data={"notification": notification_with_personalisation_schema.dump(notification).data}), 200
@notifications.route('/notifications', methods=['GET'])
def get_all_notifications():
data = notifications_filter_schema.load(request.args).data
include_jobs = data.get('include_jobs', False)
page = data.get('page', 1)
page_size = data.get('page_size', current_app.config.get('API_PAGE_SIZE'))
limit_days = data.get('limit_days')
pagination = notifications_dao.get_notifications_for_service(
str(api_user.service_id),
personalisation=True,
filter_dict=data,
page=page,
page_size=page_size,
limit_days=limit_days,
key_type=api_user.key_type,
include_jobs=include_jobs)
return jsonify(
notifications=notification_with_personalisation_schema.dump(pagination.items, many=True).data,
page_size=page_size,
total=pagination.total,
links=pagination_links(
pagination,
'.get_all_notifications',
**request.args.to_dict()
)
), 200
@notifications.route('/notifications/statistics')
def get_notification_statistics_for_day():
data = day_schema.load(request.args).data
statistics = notifications_dao.dao_get_potential_notification_statistics_for_day(
day=data['day']
)
data, errors = notifications_statistics_schema.dump(statistics, many=True)
return jsonify(data=data), 200
@notifications.route('/notifications/<string:notification_type>', methods=['POST'])
def send_notification(notification_type):
if notification_type not in ['sms', 'email']:
assert False
service = services_dao.dao_fetch_service_by_id(api_user.service_id)
notification_form, errors = (
sms_template_notification_schema if notification_type == SMS_TYPE else email_notification_schema
).load(request.get_json())
if errors:
raise InvalidRequest(errors, status_code=400)
check_service_message_limit(api_user.key_type, service)
template = templates_dao.dao_get_template_by_id_and_service_id(template_id=notification_form['template'],
service_id=service.id)
check_template_is_for_notification_type(notification_type, template.template_type)
check_template_is_active(template)
template_object = create_template_object_for_notification(template, notification_form.get('personalisation', {}))
_service_allowed_to_send_to(notification_form, service)
# Do not persist or send notification to the queue if it is a simulated recipient
simulated = simulated_recipient(notification_form['to'], notification_type)
notification_model = persist_notification(
notification_id=create_uuid(),
template_id=template.id,
template_version=template.version,
recipient=notification_form['to'],
service=service,
personalisation=notification_form.get('personalisation', None),
notification_type=notification_type,
api_key_id=api_user.id,
key_type=api_user.key_type,
simulated=simulated,
persist=False)
notification_data = {
'template': str(template.id),
'template_version': template.version,
'to': notification_form['to']
}
if notification_model.personalisation:
notification_data.update({
'personalisation': dict(notification_model.personalisation)
})
encrypted = encryption.encrypt(notification_data)
if not simulated:
tasks.send_notification_to_persist_queue(
notification_id=notification_model.id,
service=service,
template_type=template.template_type,
encrypted=encrypted,
api_key_id=str(notification_model.api_key_id),
key_type=api_user.key_type,
priority=template.process_type == PRIORITY,
research_mode=service.research_mode or api_user.key_type == KEY_TYPE_TEST
)
# queue_name = 'notify' if template.process_type == PRIORITY else None
# send_notification_to_queue(notification=notification_model,
# research_mode=service.research_mode,
# queue=queue_name)
else:
current_app.logger.info("POST simulated notification for id: {}".format(notification_model.id))
notification_form.update({"template_version": template.version})
return jsonify(
data=get_notification_return_data(
notification_model.id,
notification_form,
template_object)
), 201
def get_notification_return_data(notification_id, notification, template):
output = {
'body': str(template),
'template_version': notification['template_version'],
'notification': {'id': notification_id}
}
if template.template_type == 'email':
output.update({'subject': template.subject})
return output
def _service_allowed_to_send_to(notification, service):
if not service_allowed_to_send_to(notification['to'], service, api_user.key_type):
if api_user.key_type == KEY_TYPE_TEAM:
message = 'Cant send to this recipient using a team-only API key'
else:
message = (
'Cant send to this recipient when service is in trial mode '
' see https://www.notifications.service.gov.uk/trial-mode'
)
raise InvalidRequest(
{'to': [message]},
status_code=400
)
def create_template_object_for_notification(template, personalisation):
template_object = get_template_instance(template.__dict__, personalisation)
if template_object.missing_data:
message = 'Missing personalisation: {}'.format(", ".join(template_object.missing_data))
errors = {'template': [message]}
raise InvalidRequest(errors, status_code=400)
if (
template_object.template_type == SMS_TYPE and
template_object.content_count > current_app.config.get('SMS_CHAR_COUNT_LIMIT')
):
char_count = current_app.config.get('SMS_CHAR_COUNT_LIMIT')
message = 'Content has a character count greater than the limit of {}'.format(char_count)
errors = {'content': [message]}
raise InvalidRequest(errors, status_code=400)
return template_object