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

208 lines
6.4 KiB
Python
Raw Normal View History

2025-01-10 11:21:39 -08:00
import json
2025-01-10 14:12:45 -08:00
import os
import uuid
from flask import current_app
2017-04-27 12:41:10 +01:00
2024-01-24 07:55:14 -08:00
from app import redis_store
from app.celery import provider_tasks
from app.config import QueueNames
2021-03-10 13:55:06 +00:00
from app.dao.notifications_dao import (
dao_create_notification,
2021-03-10 13:55:06 +00:00
dao_delete_notifications_by_id,
dao_notification_exists,
2024-12-03 13:50:42 -08:00
get_notification_by_id,
2021-03-10 13:55:06 +00:00
)
2025-01-10 11:21:39 -08:00
from app.enums import NotificationStatus, NotificationType
2024-05-30 12:27:07 -07:00
from app.errors import BadRequestError
from app.models import Notification
from app.utils import hilite, utc_now
from notifications_utils.recipients import (
format_email_address,
get_international_phone_info,
validate_and_format_phone_number,
)
from notifications_utils.template import PlainTextEmailTemplate, SMSMessageTemplate
2020-05-13 11:06:27 +01:00
def create_content_for_notification(template, personalisation):
if template.template_type == NotificationType.EMAIL:
template_object = PlainTextEmailTemplate(
{
2023-08-29 14:54:30 -07:00
"content": template.content,
"subject": template.subject,
"template_type": template.template_type,
},
personalisation,
)
if template.template_type == NotificationType.SMS:
template_object = SMSMessageTemplate(
{
2023-08-29 14:54:30 -07:00
"content": template.content,
"template_type": template.template_type,
},
personalisation,
)
check_placeholders(template_object)
return template_object
def check_placeholders(template_object):
if template_object.missing_data:
2023-08-29 14:54:30 -07:00
message = "Missing personalisation: {}".format(
", ".join(template_object.missing_data)
)
raise BadRequestError(fields=[{"template": message}], message=message)
2024-12-03 13:50:42 -08:00
def get_notification(notification_id):
return get_notification_by_id(notification_id)
2017-04-27 12:41:10 +01:00
def persist_notification(
*,
2017-04-27 12:41:10 +01:00
template_id,
template_version,
recipient,
service,
personalisation,
notification_type,
api_key_id,
key_type,
created_at=None,
2017-04-27 12:41:10 +01:00
job_id=None,
job_row_number=None,
reference=None,
client_reference=None,
notification_id=None,
simulated=False,
created_by_id=None,
status=NotificationStatus.CREATED,
reply_to_text=None,
billable_units=None,
document_download_count=None,
2023-08-31 10:57:54 -04:00
updated_at=None,
2017-04-27 12:41:10 +01:00
):
2024-05-23 13:59:51 -07:00
notification_created_at = created_at or utc_now()
if not notification_id:
notification_id = uuid.uuid4()
2022-10-14 14:45:27 +00:00
current_app.logger.info(f"Persisting notification with id {notification_id}")
2022-10-14 14:45:27 +00:00
notification = Notification(
id=notification_id,
template_id=template_id,
template_version=template_version,
to=recipient,
service_id=service.id,
personalisation=personalisation,
notification_type=notification_type,
api_key_id=api_key_id,
key_type=key_type,
created_at=notification_created_at,
job_id=job_id,
job_row_number=job_row_number,
client_reference=client_reference,
reference=reference,
created_by_id=created_by_id,
2017-11-23 14:55:49 +00:00
status=status,
reply_to_text=reply_to_text,
billable_units=billable_units,
document_download_count=document_download_count,
2023-08-29 14:54:30 -07:00
updated_at=updated_at,
)
2022-10-14 14:45:27 +00:00
if notification_type == NotificationType.SMS:
2023-08-29 14:54:30 -07:00
formatted_recipient = validate_and_format_phone_number(
recipient, international=True
)
current_app.logger.info(
2024-06-06 13:18:00 -07:00
hilite(
2024-06-17 11:12:30 -07:00
f"Persisting notification with job_id: {job_id} row_number: {job_row_number}"
2024-06-06 13:18:00 -07:00
)
)
2017-04-27 12:41:10 +01:00
recipient_info = get_international_phone_info(formatted_recipient)
notification.normalised_to = formatted_recipient
2017-04-27 12:41:10 +01:00
notification.international = recipient_info.international
notification.phone_prefix = recipient_info.country_prefix
notification.rate_multiplier = recipient_info.billable_units
2024-02-01 08:06:10 -08:00
elif notification_type == NotificationType.EMAIL:
current_app.logger.info(
f"Persisting notification with type: {NotificationType.EMAIL}"
)
2024-01-24 07:55:14 -08:00
redis_store.set(
f"email-address-{notification.id}",
format_email_address(notification.to),
ex=1800,
)
2017-04-27 12:41:10 +01:00
# if simulated create a Notification model to return but do not persist the Notification to the dB
if not simulated:
if notification.notification_type == NotificationType.SMS:
2025-01-10 14:12:45 -08:00
# it's just too hard with redis and timing to test this here
if os.getenv("NOTIFY_ENVIRONMENT") == "test":
dao_create_notification(notification)
2025-03-14 08:53:40 -07:00
elif "verify_code" in str(notification.personalisation):
dao_create_notification(notification)
2025-01-10 14:12:45 -08:00
else:
redis_store.rpush(
"message_queue",
json.dumps(notification.serialize_for_redis(notification)),
)
else:
dao_create_notification(notification)
return notification
def notification_exists(notification_id):
return dao_notification_exists(notification_id)
def send_notification_to_queue_detached(
2023-08-25 12:09:00 -07:00
key_type, notification_type, notification_id, queue=None
):
if notification_type == NotificationType.SMS:
if not queue:
queue = QueueNames.SEND_SMS
deliver_task = provider_tasks.deliver_sms
if notification_type == NotificationType.EMAIL:
if not queue:
queue = QueueNames.SEND_EMAIL
deliver_task = provider_tasks.deliver_email
try:
deliver_task.apply_async([str(notification_id)], queue=queue, countdown=60)
except Exception:
dao_delete_notifications_by_id(notification_id)
raise
2018-02-02 15:55:25 +00:00
current_app.logger.debug(
f"{notification_type} {notification_id} sent to the {queue} queue for delivery"
2023-08-29 14:54:30 -07:00
)
2023-08-25 12:09:00 -07:00
def send_notification_to_queue(notification, queue=None):
send_notification_to_queue_detached(
notification.key_type,
notification.notification_type,
notification.id,
queue,
)
def simulated_recipient(to_address, notification_type):
if notification_type == NotificationType.SMS:
formatted_simulated_numbers = [
2023-08-29 14:54:30 -07:00
validate_and_format_phone_number(number)
for number in current_app.config["SIMULATED_SMS_NUMBERS"]
]
return to_address in formatted_simulated_numbers
else:
2023-08-29 14:54:30 -07:00
return to_address in current_app.config["SIMULATED_EMAIL_ADDRESSES"]