New package structure for the version 2 of the public api.

Start building up the validators required for post notificaiton.
The app/v2/errors.py is a rough sketch, will be passed a code, the error can look up the message and link for the error message.
This commit is contained in:
Rebecca Law
2016-10-25 18:04:03 +01:00
parent a5e07d8aff
commit 23a4f00e56
9 changed files with 199 additions and 1 deletions

View File

@@ -0,0 +1,14 @@
def persist_notification():
'''
persist the notification
:return:
'''
pass
def send_notificaiton_to_queue():
'''
send the notification to the queue
:return:
'''
pass

View File

@@ -0,0 +1,25 @@
from app.dao import services_dao
from app.errors import InvalidRequest
from app.models import KEY_TYPE_TEST
def check_service_message_limit(key_type, service):
if all((key_type != KEY_TYPE_TEST,
service.restricted)):
service_stats = services_dao.fetch_todays_total_message_count(service.id)
if service_stats >= service.message_limit:
error = 'Exceeded send limits ({}) for today'.format(service.message_limit)
raise InvalidRequest(error, status_code=429)
def check_template_is_for_notification_type(notification_type, template_type):
if notification_type != template_type:
raise InvalidRequest("{0} template is not suitable for {1} notification".format(template_type,
notification_type),
status_code=400)
def check_template_is_active(template):
if template.archived:
raise InvalidRequest('Template has been deleted', status_code=400)

View File

@@ -23,4 +23,4 @@ def build_error_message(errors, schema):
"fields": fields
}
return json.dumps(message)
return json.dumps(message)

0
app/v2/__init__.py Normal file
View File

29
app/v2/errors.py Normal file
View File

@@ -0,0 +1,29 @@
from flask import jsonify
from app.errors import InvalidRequest
class BadRequestError(Exception):
status_code = 400
def __init__(self, message, fields, code):
self.code = code
self.message = message
self.fields = fields
def register_errors(blueprint):
@blueprint.app_errorhandler(Exception)
def authentication_error(error):
# v2 error format - NOT this
return jsonify(result='error', message=error.message), error.code
@blueprint.app_errorhandler(InvalidRequest)
def handle_invalid_request(error):
# {
# "code",
# "link",
# "message" ,
# "fields":
# }
return "build_error_message"

View File

@@ -0,0 +1,7 @@
from flask import Blueprint
from app.v2.errors import register_errors
notification_blueprint = Blueprint(__name__, __name__, url_prefix='/v2/notifications')
register_errors(notification_blueprint)

View File

@@ -0,0 +1,14 @@
from app.v2.notifications import notification_blueprint
@notification_blueprint.route("/<uuid:id>", methods=['GET'])
def get_notification_by_id(id):
pass
@notification_blueprint.route("/", methods=['GET'])
def get_notifications():
# validate notifications request arguments
# fetch all notifications
# return notifications_response schema
pass

View File

@@ -0,0 +1,49 @@
from app.v2.notifications import notification_blueprint
@notification_blueprint.route('/sms', methods=['POST'])
def post_sms_notification():
# # get service
# service = services_dao.dao_fetch_service_by_id(api_user.service_id)
# # validate input against json schema (not marshmallow)
# form = validate(request.get_json(), post_sms_request)
#
# # following checks will be in a common function for all versions of the endpoint.
# # check service has not exceeded the sending limit
# check_service_message_limit(api_user.key_type, service)
# template = templates_dao.dao_get_template_by_id_and_service_id(
# template_id=form['template_id'],
# service_id=service.id
# )
# # check template is for sms
# check_template_is_for_notification_type(SMS_TYPE, template.template_type)
# # check template is not archived
# check_template_is_active(template)
# # check service is allowed to send
# service_can_send_to_recipient(form['phone_number'], api_user.key_type, service)
# # create body of message (create_template_object_for_notification)
# create_template_object_for_notification(template, form.get('personalisation', {}))
# # persist notification
# # send sms to provider queue for research mode queue
#
# validate post form against post_sms_request schema
# validate service
# validate template
# create content
# persist notification
# send notification to queue
# return post_sms_response schema
return "post_sms_response schema", 201
@notification_blueprint.route('/email', methods=['POST'])
def post_email_notification():
# validate post form against post_email_request schema
# validate service
# validate template
# persist notification
# send notification to queue
# create content
# return post_email_response schema
pass

View File

@@ -0,0 +1,60 @@
import pytest
from app.errors import InvalidRequest
from app.notifications.validators import check_service_message_limit, check_template_is_for_notification_type, \
check_template_is_active
from tests.app.conftest import (sample_notification as create_notification,
sample_service as create_service)
@pytest.mark.parametrize('key_type', ['test', 'team', 'live'])
def test_check_service_message_limit_with_unrestricted_service_passes(key_type,
sample_service,
sample_notification):
assert check_service_message_limit(key_type, sample_service) is None
@pytest.mark.parametrize('key_type', ['test', 'team', 'live'])
def test_check_service_message_limit_under_message_limit_passes(key_type,
sample_service,
sample_notification):
assert check_service_message_limit(key_type, sample_service) is None
@pytest.mark.parametrize('key_type', ['team', 'live'])
def test_check_service_message_limit_over_message_limit_fails(key_type, notify_db, notify_db_session):
service = create_service(notify_db, notify_db_session, restricted=True, limit=4)
for x in range(5):
create_notification(notify_db, notify_db_session, service=service)
with pytest.raises(InvalidRequest):
check_service_message_limit(key_type, service)
@pytest.mark.parametrize('template_type, notification_type',
[('email', 'email'),
('sms', 'sms')])
def test_check_template_is_for_notification_type_pass(template_type, notification_type):
assert check_template_is_for_notification_type(notification_type=notification_type,
template_type=template_type) is None
@pytest.mark.parametrize('template_type, notification_type',
[('sms', 'email'),
('email', 'sms')])
def test_check_template_is_for_notification_type_fails_when_template_type_does_not_match_notification_type(
template_type, notification_type):
with pytest.raises(InvalidRequest):
check_template_is_for_notification_type(notification_type=notification_type,
template_type=template_type)
def test_check_template_is_active_passes(sample_template):
assert check_template_is_active(sample_template) is None
def test_check_template_is_active_passes(sample_template):
sample_template.archived = True
from app.dao.templates_dao import dao_update_template
dao_update_template(sample_template)
with pytest.raises(InvalidRequest):
check_template_is_active(sample_template)