From 38e5b31e9accb368e28c6011b1591598fcaec9ec Mon Sep 17 00:00:00 2001 From: Rebecca Law Date: Mon, 15 May 2017 15:02:38 +0100 Subject: [PATCH] Update notification schemas with optional schedule_for element --- app/schema_validation/__init__.py | 11 +++++ app/v2/notifications/notification_schemas.py | 15 ++++--- .../test_notification_schemas.py | 42 +++++++++++++++++-- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/app/schema_validation/__init__.py b/app/schema_validation/__init__.py index 376315a8a..fc134e2ce 100644 --- a/app/schema_validation/__init__.py +++ b/app/schema_validation/__init__.py @@ -1,4 +1,5 @@ import json +from datetime import datetime from jsonschema import (Draft4Validator, ValidationError, FormatChecker) from notifications_utils.recipients import (validate_phone_number, validate_email_address, InvalidPhoneError, @@ -20,6 +21,16 @@ def validate(json_to_validate, schema): validate_email_address(instance) return True + @format_checker.checks('datetime', raises=ValidationError) + def validate_schema_datetime(instance): + if isinstance(instance, str): + try: + datetime.strptime(instance, "%Y-%m-%d %H:%M:%S") + except ValueError as e: + raise ValidationError("datetime format is invalid. Use the format: " + "YYYY-MM-DD HH:MM:SS, for example 2017-05-30 13:00:00") + return True + validator = Draft4Validator(schema, format_checker=format_checker) errors = list(validator.iter_errors(json_to_validate)) if errors.__len__() > 0: diff --git a/app/v2/notifications/notification_schemas.py b/app/v2/notifications/notification_schemas.py index 240d41324..8777b49ba 100644 --- a/app/v2/notifications/notification_schemas.py +++ b/app/v2/notifications/notification_schemas.py @@ -39,7 +39,8 @@ get_notification_response = { "subject": {"type": ["string", "null"]}, "created_at": {"type": "string"}, "sent_at": {"type": ["string", "null"]}, - "completed_at": {"type": ["string", "null"]} + "completed_at": {"type": ["string", "null"]}, + "scheduled_for": {"type": ["string", "null"]} }, "required": [ # technically, all keys are required since we always have all of them @@ -111,7 +112,8 @@ post_sms_request = { "reference": {"type": "string"}, "phone_number": {"type": "string", "format": "phone_number"}, "template_id": uuid, - "personalisation": personalisation + "personalisation": personalisation, + "scheduled_for": {"type": "string", "format": "datetime"} }, "required": ["phone_number", "template_id"] } @@ -138,7 +140,8 @@ post_sms_response = { "reference": {"type": ["string", "null"]}, "content": sms_content, "uri": {"type": "string", "format": "uri"}, - "template": template + "template": template, + "scheduled_for": {"type": "string"} }, "required": ["id", "content", "uri", "template"] } @@ -153,7 +156,8 @@ post_email_request = { "reference": {"type": "string"}, "email_address": {"type": "string", "format": "email_address"}, "template_id": uuid, - "personalisation": personalisation + "personalisation": personalisation, + "scheduled_for": {"type": "string", "format": "datetime"} }, "required": ["email_address", "template_id"] } @@ -181,7 +185,8 @@ post_email_response = { "reference": {"type": ["string", "null"]}, "content": email_content, "uri": {"type": "string", "format": "uri"}, - "template": template + "template": template, + "scheduled_for": {"type": "string"} }, "required": ["id", "content", "uri", "template"] } diff --git a/tests/app/v2/notifications/test_notification_schemas.py b/tests/app/v2/notifications/test_notification_schemas.py index 65a03b84d..44794f9de 100644 --- a/tests/app/v2/notifications/test_notification_schemas.py +++ b/tests/app/v2/notifications/test_notification_schemas.py @@ -246,7 +246,8 @@ def valid_email_response(): "id": str(uuid.uuid4()), "version": 1, "uri": "http://notify.api/v2/template/id" - } + }, + "scheduled_for": "" } @@ -262,7 +263,8 @@ def valid_email_response_with_optionals(): "id": str(uuid.uuid4()), "version": 1, "uri": "http://notify.api/v2/template/id" - } + }, + "schedule_for": "2017-05-12 13:00:00" } @@ -346,7 +348,41 @@ def test_get_notifications_response_with_email_and_phone_number(): "subject": "some subject", "created_at": "2016-01-01", "sent_at": "2016-01-01", - "completed_at": "2016-01-01" + "completed_at": "2016-01-01", + "schedule_for": "" } assert validate(response, get_notification_response) == response + + +@pytest.mark.parametrize("schema", + [post_email_request_schema, post_sms_request_schema]) +def test_post_schema_valid_scheduled_for(schema): + j = {"template_id": str(uuid.uuid4()), + "email_address": "joe@gmail.com", + "scheduled_for": "2017-05-12 13:00:00"} + if schema == post_email_request_schema: + j.update({"email_address": "joe@gmail.com"}) + else: + j.update({"phone_number": "07515111111"}) + assert validate(j, schema) == j + + +@pytest.mark.parametrize("invalid_datetime", + ["2017-05-12 13:00", "13:00:00 2017-01-01"]) +@pytest.mark.parametrize("schema", + [post_email_request_schema, post_sms_request_schema]) +def test_post_email_schema_invalid_scheduled_for(invalid_datetime, schema): + j = {"template_id": str(uuid.uuid4()), + "scheduled_for": invalid_datetime} + if schema == post_email_request_schema: + j.update({"email_address": "joe@gmail.com"}) + else: + j.update({"phone_number": "07515111111"}) + with pytest.raises(ValidationError) as e: + validate(j, schema) + error = json.loads(str(e.value)) + assert error['status_code'] == 400 + assert error['errors'] == [{'error': 'ValidationError', + 'message': "scheduled_for datetime format is invalid. Use the format: " + "YYYY-MM-DD HH:MM:SS, for example 2017-05-30 13:00:00"}]