mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-04 10:21:14 -05:00
- Implemented persist_notification and send_notification_to_queue in the process_notifications module
- Not sure I want to create a new classmethod on Notifications to create from v2 request. Will take another look at that.
This commit is contained in:
@@ -22,7 +22,7 @@ from app.authentication.utils import get_secret
|
||||
from app import (
|
||||
db,
|
||||
encryption,
|
||||
DATETIME_FORMAT)
|
||||
DATETIME_FORMAT, create_uuid)
|
||||
|
||||
from app.history_meta import Versioned
|
||||
|
||||
@@ -562,6 +562,30 @@ class Notification(db.Model):
|
||||
key_type=key_type
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_v2_api_request(cls,
|
||||
template_id,
|
||||
template_version,
|
||||
recipient,
|
||||
service_id,
|
||||
personalisation,
|
||||
notification_type,
|
||||
api_key_id,
|
||||
key_type):
|
||||
return cls(
|
||||
id=create_uuid(),
|
||||
template_id=template_id,
|
||||
template_version=template_version,
|
||||
to=recipient,
|
||||
service_id=service_id,
|
||||
status='created',
|
||||
created_at=datetime.datetime.strftime(datetime.datetime.utcnow(), DATETIME_FORMAT),
|
||||
personalisation=personalisation,
|
||||
notification_type=notification_type,
|
||||
api_key_id=api_key_id,
|
||||
key_type=key_type
|
||||
)
|
||||
|
||||
|
||||
class NotificationHistory(db.Model):
|
||||
__tablename__ = 'notification_history'
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
from flask import current_app
|
||||
from notifications_utils.renderers import PassThrough
|
||||
from notifications_utils.template import Template
|
||||
|
||||
from app.models import SMS_TYPE
|
||||
from app.celery import provider_tasks
|
||||
from app.dao.notifications_dao import dao_create_notification, dao_delete_notifications_and_history_by_id
|
||||
from app.errors import InvalidRequest
|
||||
from app.models import SMS_TYPE, Notification, KEY_TYPE_TEST, EMAIL_TYPE
|
||||
from app.notifications.validators import check_sms_content_char_count
|
||||
from app.v2.errors import BadRequestError
|
||||
|
||||
@@ -27,17 +31,44 @@ def create_content_for_notification(template, personalisation):
|
||||
return template_object
|
||||
|
||||
|
||||
def persist_notification():
|
||||
'''
|
||||
persist the notification
|
||||
:return:
|
||||
'''
|
||||
pass
|
||||
def persist_notification(template_id,
|
||||
template_version,
|
||||
recipient,
|
||||
service_id,
|
||||
personalisation,
|
||||
notification_type,
|
||||
api_key_id,
|
||||
key_type):
|
||||
notification = Notification.from_v2_api_request(template_id,
|
||||
template_version,
|
||||
recipient,
|
||||
service_id,
|
||||
personalisation,
|
||||
notification_type,
|
||||
api_key_id,
|
||||
key_type)
|
||||
dao_create_notification(notification)
|
||||
return notification
|
||||
|
||||
|
||||
def send_notificaiton_to_queue():
|
||||
'''
|
||||
send the notification to the queue
|
||||
:return:
|
||||
'''
|
||||
pass
|
||||
def send_notification_to_queue(notification, research_mode):
|
||||
try:
|
||||
research_mode = research_mode or notification.key_type == KEY_TYPE_TEST
|
||||
if notification.notification_type == SMS_TYPE:
|
||||
provider_tasks.deliver_sms.apply_async(
|
||||
[str(notification.id)],
|
||||
queue='send-sms' if not research_mode else 'research-mode'
|
||||
)
|
||||
if notification.notification_type == EMAIL_TYPE:
|
||||
provider_tasks.deliver_email.apply_async(
|
||||
[str(notification.id)],
|
||||
queue='send-email' if not research_mode else 'research-mode'
|
||||
)
|
||||
except Exception as e:
|
||||
current_app.logger.exception("Failed to send to SQS exception")
|
||||
dao_delete_notifications_and_history_by_id(notification.id)
|
||||
raise InvalidRequest(message="Internal server error", status_code=500)
|
||||
|
||||
current_app.logger.info(
|
||||
"{} {} created at {}".format(notification.notification_type, notification.id, notification.created_at)
|
||||
)
|
||||
|
||||
@@ -54,3 +54,14 @@ post_sms_response = {
|
||||
},
|
||||
"required": ["id", "content", "uri", "template"]
|
||||
}
|
||||
|
||||
|
||||
def create_post_sms_response_from_notification(notification, content):
|
||||
return {"id": notification.id,
|
||||
"reference": None, # not yet implemented
|
||||
"content": content,
|
||||
"uri": "v2/notifications/{}".format(notification.id),
|
||||
"template": {"id": notification.template_id,
|
||||
"version": notification.template_version,
|
||||
"uri": "v2/templates/{}".format(notification.template_id)}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from flask import request
|
||||
|
||||
from flask import request, jsonify
|
||||
from app import api_user
|
||||
from app.dao import services_dao, templates_dao
|
||||
from app.models import SMS_TYPE
|
||||
from app.notifications.process_notifications import create_content_for_notification
|
||||
from app.notifications.process_notifications import create_content_for_notification, persist_notification, \
|
||||
send_notification_to_queue
|
||||
from app.notifications.validators import (check_service_message_limit,
|
||||
check_template_is_for_notification_type,
|
||||
check_template_is_active,
|
||||
@@ -11,7 +11,8 @@ from app.notifications.validators import (check_service_message_limit,
|
||||
check_sms_content_char_count)
|
||||
from app.schema_validation import validate
|
||||
from app.v2.notifications import notification_blueprint
|
||||
from app.v2.notifications.notification_schemas import post_sms_request
|
||||
from app.v2.notifications.notification_schemas import (post_sms_request,
|
||||
create_post_sms_response_from_notification)
|
||||
|
||||
|
||||
@notification_blueprint.route('/sms', methods=['POST'])
|
||||
@@ -34,9 +35,17 @@ def post_sms_notification():
|
||||
check_sms_content_char_count(template_with_content.replaced_content_count)
|
||||
|
||||
# persist notification
|
||||
# send sms to provider queue for research mode queue
|
||||
# return post_sms_response schema
|
||||
return "post_sms_response schema", 201
|
||||
notification = persist_notification(template_id=template.id,
|
||||
template_version=template.version,
|
||||
recipient=form['phone_number'],
|
||||
service_id=service.id,
|
||||
personalisation=form.get('personalisation', None),
|
||||
notification_type=SMS_TYPE,
|
||||
api_key_id=api_user.id,
|
||||
key_type=api_user.key_type)
|
||||
send_notification_to_queue(notification, service.research_mode)
|
||||
resp = create_post_sms_response_from_notification(notification, template_with_content.content)
|
||||
return jsonify(resp), 201
|
||||
|
||||
|
||||
@notification_blueprint.route('/email', methods=['POST'])
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import pytest
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from app.models import Template
|
||||
from app.notifications.process_notifications import create_content_for_notification
|
||||
from app.errors import InvalidRequest
|
||||
from app.models import Template, Notification, NotificationHistory
|
||||
from app.notifications.process_notifications import (create_content_for_notification,
|
||||
persist_notification, send_notification_to_queue)
|
||||
from app.v2.errors import BadRequestError
|
||||
from tests.app.conftest import sample_notification, sample_template, sample_email_template
|
||||
|
||||
|
||||
def test_create_content_for_notification_passes(sample_email_template):
|
||||
@@ -15,3 +19,51 @@ def test_create_content_for_notification_fails_with_missing_personalisation(samp
|
||||
template = Template.query.get(sample_template_with_placeholders.id)
|
||||
with pytest.raises(BadRequestError):
|
||||
create_content_for_notification(template, None)
|
||||
|
||||
|
||||
def test_persist_notification_creates_and_save_to_db(sample_template, sample_api_key):
|
||||
assert Notification.query.count() == 0
|
||||
assert NotificationHistory.query.count() == 0
|
||||
notification = persist_notification(sample_template.id, sample_template.version, '+447111111111',
|
||||
sample_template.service.id, {}, 'sms', sample_api_key.id,
|
||||
sample_api_key.key_type)
|
||||
assert Notification.query.count() == 1
|
||||
assert Notification.query.get(notification.id).__eq__(notification)
|
||||
assert NotificationHistory.query.count() == 1
|
||||
|
||||
|
||||
def test_persist_notification_throws_exception_when_missing_template(sample_template, sample_api_key):
|
||||
assert Notification.query.count() == 0
|
||||
with pytest.raises(SQLAlchemyError):
|
||||
persist_notification(template_id=None,
|
||||
template_version=None,
|
||||
recipient='+447111111111',
|
||||
service_id=sample_template.service.id,
|
||||
personalisation=None, notification_type='sms',
|
||||
api_key_id=sample_api_key.id,
|
||||
key_type=sample_api_key.key_type)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('research_mode, queue, notification_type, key_type',
|
||||
[(True, 'research-mode', 'sms', 'normal'),
|
||||
(False, 'send-sms', 'sms', 'normal'),
|
||||
(True, 'research-mode', 'email', 'normal'),
|
||||
(False, 'send-email', 'email', 'normal'),
|
||||
(False, 'research-mode', 'sms', 'test')])
|
||||
def test_send_notification_to_queue(notify_db, notify_db_session,
|
||||
research_mode, notification_type,
|
||||
queue, key_type, mocker):
|
||||
mocked = mocker.patch('app.celery.provider_tasks.deliver_{}.apply_async'.format(notification_type))
|
||||
template = sample_template(notify_db, notify_db_session) if notification_type == 'sms' \
|
||||
else sample_email_template(notify_db, notify_db_session)
|
||||
notification = sample_notification(notify_db, notify_db_session, template=template, key_type=key_type)
|
||||
send_notification_to_queue(notification=notification, research_mode=research_mode)
|
||||
|
||||
mocked.assert_called_once_with([str(notification.id)], queue=queue)
|
||||
|
||||
|
||||
def test_send_notification_to_queue(sample_notification, mocker):
|
||||
mocked = mocker.patch('app.celery.provider_tasks.deliver_sms.apply_async', side_effect=Exception("EXPECTED"))
|
||||
with pytest.raises(InvalidRequest):
|
||||
send_notification_to_queue(sample_notification, False)
|
||||
mocked.assert_called_once_with([(str(sample_notification.id))], queue='send-sms')
|
||||
|
||||
@@ -3,9 +3,10 @@ from flask import json
|
||||
from tests import create_authorization_header
|
||||
|
||||
|
||||
def test_post_sms_notification_returns_201(notify_api, sample_template):
|
||||
def test_post_sms_notification_returns_201(notify_api, sample_template, mocker):
|
||||
with notify_api.test_request_context():
|
||||
with notify_api.test_client() as client:
|
||||
mocked = mocker.patch('app.celery.provider_tasks.deliver_sms.apply_async')
|
||||
data = {
|
||||
'phone_number': '+447700900855',
|
||||
'template_id': str(sample_template.id)
|
||||
@@ -18,6 +19,12 @@ def test_post_sms_notification_returns_201(notify_api, sample_template):
|
||||
headers=[('Content-Type', 'application/json'), auth_header])
|
||||
|
||||
assert response.status_code == 201
|
||||
resp_json = json.loads(response.get_data(as_text=True))
|
||||
assert resp_json['id'] is not None
|
||||
assert resp_json['reference'] is None
|
||||
assert resp_json['template']['id'] == str(sample_template.id)
|
||||
assert resp_json['template']['version'] == sample_template.version
|
||||
assert mocked.called
|
||||
|
||||
|
||||
def test_post_sms_notification_returns_404_when_template_is_wrong_type(notify_api, sample_email_template):
|
||||
|
||||
Reference in New Issue
Block a user