Files
notifications-api/app/notifications/rest.py

208 lines
7.5 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
)
from app import api_user, authenticated_service
from app.dao import (
templates_dao,
notifications_dao
)
from app.models import KEY_TYPE_TEAM, PRIORITY
from app.models import SMS_TYPE
from app.notifications.process_notifications import (
persist_notification,
send_notification_to_queue,
simulated_recipient
)
from app.notifications.validators import (
check_template_is_for_notification_type,
check_template_is_active,
check_rate_limiting
)
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
from notifications_utils.recipients import get_international_phone_info
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(authenticated_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(authenticated_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
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_rate_limiting(authenticated_service, api_user)
template = templates_dao.dao_get_template_by_id_and_service_id(
template_id=notification_form['template'],
service_id=authenticated_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, authenticated_service)
if notification_type == SMS_TYPE:
_service_can_send_internationally(authenticated_service, notification_form['to'])
# 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(template_id=template.id,
template_version=template.version,
recipient=request.get_json()['to'],
service=authenticated_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)
if not simulated:
queue_name = 'priority' if template.process_type == PRIORITY else None
send_notification_to_queue(notification=notification_model,
research_mode=authenticated_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_can_send_internationally(service, number):
international_phone_info = get_international_phone_info(number)
if international_phone_info.international and not service.can_send_international_sms:
raise InvalidRequest(
{'to': ["Cannot send to international mobile numbers"]},
status_code=400
)
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