mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-01 15:46:07 -05:00
Adds notification stats update into the callback process
- when a provider callback occurs and we update the status of the notification, also update the statistics table Adds: - Mapping object to the clients to handle mapping to various states from the response codes, this replaces the map. - query lookup in the DAO to get the query based on response type / template type Tests around rest class and dao to check correct updating of stats Missing: - multiple client callbacks will keep incrementing the counts of success/failure. This edge case needs to be handle in a future story.
This commit is contained in:
@@ -13,6 +13,11 @@ class Client(object):
|
||||
pass
|
||||
|
||||
|
||||
STATISTICS_REQUESTED = 'requested'
|
||||
STATISTICS_DELIVERED = 'delivered'
|
||||
STATISTICS_FAILURE = 'failure'
|
||||
|
||||
|
||||
class ClientResponse:
|
||||
def __init__(self):
|
||||
self.__response_model__ = None
|
||||
@@ -24,7 +29,6 @@ class ClientResponse:
|
||||
return self.response_code_to_object(response_code)['message']
|
||||
|
||||
def response_code_to_notification_status(self, response_code):
|
||||
print(response_code)
|
||||
return self.response_code_to_object(response_code)['notification_status']
|
||||
|
||||
def response_code_to_notification_statistics_status(self, response_code):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import boto3
|
||||
from flask import current_app
|
||||
from monotonic import monotonic
|
||||
from app.clients import ClientResponse
|
||||
from app.clients import ClientResponse, STATISTICS_DELIVERED, STATISTICS_FAILURE
|
||||
from app.clients.email import (EmailClientException, EmailClient)
|
||||
|
||||
|
||||
@@ -13,19 +13,19 @@ class AwsSesResponses(ClientResponse):
|
||||
"message": 'Bounced',
|
||||
"success": False,
|
||||
"notification_status": 'bounce',
|
||||
"notification_statistics_status": 'failed'
|
||||
"notification_statistics_status": STATISTICS_FAILURE
|
||||
},
|
||||
'Delivery': {
|
||||
"message": 'Delivered',
|
||||
"success": True,
|
||||
"notification_status": 'delivered',
|
||||
"notification_statistics_status": 'delivered'
|
||||
"notification_statistics_status": STATISTICS_DELIVERED
|
||||
},
|
||||
'Complaint': {
|
||||
"message": 'Complaint',
|
||||
"success": False,
|
||||
"notification_status": 'complaint',
|
||||
"notification_statistics_status": 'failed'
|
||||
"notification_statistics_status": STATISTICS_FAILURE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from app.clients.sms import (
|
||||
)
|
||||
from flask import current_app
|
||||
from requests import request, RequestException, HTTPError
|
||||
from app.clients import ClientResponse
|
||||
from app.clients import ClientResponse, STATISTICS_DELIVERED, STATISTICS_FAILURE
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -17,14 +17,14 @@ class FiretextResponses(ClientResponse):
|
||||
self.__response_model__ = {
|
||||
'0': {
|
||||
"message": 'Delivered',
|
||||
"notification_statistics_status": 'delivered',
|
||||
"notification_statistics_status": STATISTICS_DELIVERED,
|
||||
"success": True,
|
||||
"notification_status": 'delivered'
|
||||
},
|
||||
'1': {
|
||||
"message": 'Declined',
|
||||
"success": False,
|
||||
"notification_statistics_status": 'failed',
|
||||
"notification_statistics_status": STATISTICS_FAILURE,
|
||||
"notification_status": 'failed'
|
||||
},
|
||||
'2': {
|
||||
|
||||
@@ -3,7 +3,8 @@ from app import db
|
||||
from app.models import Notification, Job, NotificationStatistics, TEMPLATE_TYPE_SMS, TEMPLATE_TYPE_EMAIL
|
||||
from sqlalchemy import desc
|
||||
from datetime import datetime, timedelta
|
||||
from app.clients.sms.firetext import FiretextResponses
|
||||
from app.clients import (STATISTICS_FAILURE, STATISTICS_DELIVERED, STATISTICS_REQUESTED)
|
||||
|
||||
|
||||
def dao_get_notification_statistics_for_service(service_id):
|
||||
return NotificationStatistics.query.filter_by(
|
||||
@@ -49,18 +50,16 @@ def dao_create_notification(notification, notification_type):
|
||||
|
||||
|
||||
def update_query(notification_type, status):
|
||||
print(notification_type)
|
||||
print(status)
|
||||
mapping = {
|
||||
'sms': {
|
||||
'requested': NotificationStatistics.sms_requested,
|
||||
'success': NotificationStatistics.sms_delivered,
|
||||
'failure': NotificationStatistics.sms_error
|
||||
TEMPLATE_TYPE_SMS: {
|
||||
STATISTICS_REQUESTED: NotificationStatistics.sms_requested,
|
||||
STATISTICS_DELIVERED: NotificationStatistics.sms_delivered,
|
||||
STATISTICS_FAILURE: NotificationStatistics.sms_error
|
||||
},
|
||||
'email': {
|
||||
'requested': NotificationStatistics.emails_requested,
|
||||
'success': NotificationStatistics.emails_delivered,
|
||||
'failure': NotificationStatistics.emails_error
|
||||
TEMPLATE_TYPE_EMAIL: {
|
||||
STATISTICS_REQUESTED: NotificationStatistics.emails_requested,
|
||||
STATISTICS_DELIVERED: NotificationStatistics.emails_delivered,
|
||||
STATISTICS_FAILURE: NotificationStatistics.emails_error
|
||||
}
|
||||
}
|
||||
return {
|
||||
@@ -74,29 +73,46 @@ def dao_update_notification(notification):
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def update_notification_status_by_id(notification_id, status):
|
||||
def update_notification_status_by_id(notification_id, status, notification_statistics_status):
|
||||
count = db.session.query(Notification).filter_by(
|
||||
id=notification_id
|
||||
).update({
|
||||
Notification.status: status
|
||||
})
|
||||
if count == 1:
|
||||
|
||||
if count == 1 and notification_statistics_status:
|
||||
notification = Notification.query.get(notification_id)
|
||||
|
||||
db.session.query(NotificationStatistics).filter_by(
|
||||
day=notification.created_at.strftime('%Y-%m-%d'),
|
||||
service_id=notification.service_id
|
||||
).update(update_query(notification.template.template_type, FiretextResponses.response_code_to_notify_stats(status)))
|
||||
).update(
|
||||
update_query(notification.template.template_type, notification_statistics_status)
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
return count
|
||||
|
||||
|
||||
def update_notification_status_by_reference(reference, status):
|
||||
def update_notification_status_by_reference(reference, status, notification_statistics_status):
|
||||
count = db.session.query(Notification).filter_by(
|
||||
reference=reference
|
||||
).update({
|
||||
Notification.status: status
|
||||
})
|
||||
|
||||
if count == 1:
|
||||
notification = Notification.query.filter_by(
|
||||
reference=reference
|
||||
).first()
|
||||
|
||||
db.session.query(NotificationStatistics).filter_by(
|
||||
day=notification.created_at.strftime('%Y-%m-%d'),
|
||||
service_id=notification.service_id
|
||||
).update(
|
||||
update_query(notification.template.template_type, notification_statistics_status)
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
return count
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ from flask import (
|
||||
)
|
||||
|
||||
from utils.template import Template
|
||||
from app.clients.sms.firetext import firetext_response_status
|
||||
from app.clients.email.aws_ses import ses_response_status
|
||||
from app.clients.sms.firetext import FiretextResponses
|
||||
from app.clients.email.aws_ses import AwsSesResponses
|
||||
from app import api_user, encryption, create_uuid, DATETIME_FORMAT, DATE_FORMAT
|
||||
from app.authentication.auth import require_admin
|
||||
from app.dao import (
|
||||
@@ -34,6 +34,9 @@ from app.errors import register_errors
|
||||
|
||||
register_errors(notifications)
|
||||
|
||||
aws_response = AwsSesResponses()
|
||||
firetext_response = FiretextResponses()
|
||||
|
||||
|
||||
@notifications.route('/notifications/email/ses', methods=['POST'])
|
||||
def process_ses_response():
|
||||
@@ -57,35 +60,54 @@ def process_ses_response():
|
||||
result="error", message="SES callback failed: notificationType missing"
|
||||
), 400
|
||||
|
||||
status = ses_response_status.get(ses_message['notificationType'], None)
|
||||
if not status:
|
||||
try:
|
||||
aws_response.response_code_to_object(ses_message['notificationType'])
|
||||
except KeyError:
|
||||
current_app.logger.info(
|
||||
"SES callback failed: status {} not found.".format(status)
|
||||
"SES callback failed: status {} not found.".format(ses_message['notificationType'])
|
||||
)
|
||||
return jsonify(
|
||||
result="error",
|
||||
message="SES callback failed: status {} not found".format(ses_message['notificationType'])
|
||||
), 400
|
||||
|
||||
notification_status = aws_response.response_code_to_notification_status(ses_message['notificationType'])
|
||||
notification_statistics_status = aws_response.response_code_to_notification_statistics_status(
|
||||
ses_message['notificationType']
|
||||
)
|
||||
|
||||
try:
|
||||
source = ses_message['mail']['source']
|
||||
if is_not_a_notification(source):
|
||||
current_app.logger.info(
|
||||
"SES callback for notify success:. source {} status {}".format(source, status['notify_status'])
|
||||
"SES callback for notify success:. source {} status {}".format(source, notification_status)
|
||||
)
|
||||
return jsonify(
|
||||
result="success", message="SES callback succeeded"
|
||||
), 200
|
||||
|
||||
reference = ses_message['mail']['messageId']
|
||||
if notifications_dao.update_notification_status_by_reference(reference, status['notify_status']) == 0:
|
||||
if notifications_dao.update_notification_status_by_reference(
|
||||
reference,
|
||||
notification_status,
|
||||
notification_statistics_status
|
||||
) == 0:
|
||||
current_app.logger.info(
|
||||
"SES callback failed: notification not found. Status {}".format(status['notify_status'])
|
||||
"SES callback failed: notification not found. Status {}".format(notification_status)
|
||||
)
|
||||
return jsonify(
|
||||
result="error",
|
||||
message="SES callback failed: notification not found. Status {}".format(status['notify_status'])
|
||||
message="SES callback failed: notification not found. Status {}".format(notification_status)
|
||||
), 404
|
||||
|
||||
if not aws_response.response_code_to_notification_success(ses_message['notificationType']):
|
||||
current_app.logger.info(
|
||||
"SES delivery failed: notification {} has error found. Status {}".format(
|
||||
reference,
|
||||
aws_response.response_code_to_message(ses_message['notificationType'])
|
||||
)
|
||||
)
|
||||
|
||||
return jsonify(
|
||||
result="success", message="SES callback succeeded"
|
||||
), 200
|
||||
@@ -149,14 +171,22 @@ def process_firetext_response():
|
||||
result="error", message="Firetext callback with invalid reference {}".format(reference)
|
||||
), 400
|
||||
|
||||
notification_status = firetext_response_status.get(status, None)
|
||||
if not notification_status:
|
||||
try:
|
||||
firetext_response.response_code_to_object(status)
|
||||
except KeyError:
|
||||
current_app.logger.info(
|
||||
"Firetext callback failed: status {} not found.".format(status)
|
||||
)
|
||||
return jsonify(result="error", message="Firetext callback failed: status {} not found.".format(status)), 400
|
||||
|
||||
if notifications_dao.update_notification_status_by_id(reference, notification_status['notify_status']) == 0:
|
||||
notification_status = firetext_response.response_code_to_notification_status(status)
|
||||
notification_statistics_status = firetext_response.response_code_to_notification_statistics_status(status)
|
||||
|
||||
if notifications_dao.update_notification_status_by_id(
|
||||
reference,
|
||||
notification_status,
|
||||
notification_statistics_status
|
||||
) == 0:
|
||||
current_app.logger.info(
|
||||
"Firetext callback failed: notification {} not found. Status {}".format(reference, status)
|
||||
)
|
||||
@@ -164,15 +194,15 @@ def process_firetext_response():
|
||||
result="error",
|
||||
message="Firetext callback failed: notification {} not found. Status {}".format(
|
||||
reference,
|
||||
notification_status['firetext_message']
|
||||
firetext_response.response_code_to_message(status)
|
||||
)
|
||||
), 404
|
||||
|
||||
if not notification_status['success']:
|
||||
if not firetext_response.response_code_to_notification_success(status):
|
||||
current_app.logger.info(
|
||||
"Firetext delivery failed: notification {} has error found. Status {}".format(
|
||||
reference,
|
||||
firetext_response_status[status]['firetext_message']
|
||||
FiretextResponses().response_code_to_message(status)
|
||||
)
|
||||
)
|
||||
return jsonify(
|
||||
|
||||
Reference in New Issue
Block a user