mirror of
https://github.com/GSA/notifications-api.git
synced 2025-12-21 07:51:13 -05:00
This PR changes the response to POST /notifications/sms/<mmg | firetext> from a 400 response to a 200 response. If we get a callback for a notification more than once or for a notification we log that but we return a 200 success response to the provider. We have found that there is a situation where the send to provider throws a timeout exception but the provider did get the message, but we still send it to them again. In which case they send the message twice, and callback for the message twice. Another case where we may get duplicate callbacks is that the network gave the provider two callbacks meaning they pass those two callbacks onto us. So it is really difficult to know if we sent to the provider twice or just got two callbacks. The test_callback has many changes because I took the opportunity to use the client conftest fixture rather than the notify_api fixture. The only 2 tests really changed are test_mmg_callback_returns_200_when_notification_id_not_found_or_already_updated and test_firetext_callback_returns_200_when_notification_id_not_found_or_already_updated
82 lines
3.1 KiB
Python
82 lines
3.1 KiB
Python
import uuid
|
|
|
|
from datetime import datetime
|
|
from flask import current_app
|
|
|
|
from app import statsd_client
|
|
from app.dao import notifications_dao
|
|
from app.clients.sms.firetext import get_firetext_responses
|
|
from app.clients.sms.mmg import get_mmg_responses
|
|
|
|
sms_response_mapper = {
|
|
'MMG': get_mmg_responses,
|
|
'Firetext': get_firetext_responses
|
|
}
|
|
|
|
|
|
def validate_callback_data(data, fields, client_name):
|
|
errors = []
|
|
for f in fields:
|
|
if not str(data.get(f, '')):
|
|
error = "{} callback failed: {} missing".format(client_name, f)
|
|
errors.append(error)
|
|
return errors if len(errors) > 0 else None
|
|
|
|
|
|
def process_sms_client_response(status, reference, client_name):
|
|
success = None
|
|
errors = None
|
|
# validate reference
|
|
if reference == 'send-sms-code':
|
|
success = "{} callback succeeded: send-sms-code".format(client_name)
|
|
return success, errors
|
|
|
|
try:
|
|
uuid.UUID(reference, version=4)
|
|
except ValueError:
|
|
message = "{} callback with invalid reference {}".format(client_name, reference)
|
|
return success, message
|
|
|
|
try:
|
|
response_parser = sms_response_mapper[client_name]
|
|
except KeyError:
|
|
return success, 'unknown sms client: {}'.format(client_name)
|
|
|
|
# validate status
|
|
try:
|
|
response_dict = response_parser(status)
|
|
current_app.logger.info('{} callback return status of {} for reference: {}'.format(client_name,
|
|
status, reference))
|
|
except KeyError:
|
|
msg = "{} callback failed: status {} not found.".format(client_name, status)
|
|
return success, msg
|
|
|
|
notification_status = response_dict['notification_status']
|
|
notification_status_message = response_dict['message']
|
|
notification_success = response_dict['success']
|
|
|
|
# record stats
|
|
notification = notifications_dao.update_notification_status_by_id(reference, notification_status)
|
|
if not notification:
|
|
current_app.logger.info("{} callback failed: notification {} either not found or already updated "
|
|
"from sending. Status {}".format(client_name,
|
|
reference,
|
|
notification_status_message))
|
|
return success, errors
|
|
|
|
if not notification_success:
|
|
current_app.logger.info(
|
|
"{} delivery failed: notification {} has error found. Status {}".format(client_name,
|
|
reference,
|
|
notification_status_message))
|
|
|
|
statsd_client.incr('callback.{}.{}'.format(client_name.lower(), notification_status))
|
|
if notification.sent_at:
|
|
statsd_client.timing_with_dates(
|
|
'callback.{}.elapsed-time'.format(client_name.lower()),
|
|
datetime.utcnow(),
|
|
notification.sent_at
|
|
)
|
|
success = "{} callback succeeded. reference {} updated".format(client_name, reference)
|
|
return success, errors
|