add broadcast to template_types and add broadcast_data

had to go through the code and change a few places where we filter on
template types. i specifically didn't worry about jobs or notifications.

Also, add braodcast_data - a json column that might contain arbitrary
broadcast data that we'll figure out as we go. We don't know what it'll
look like, but it should be returned by the API
This commit is contained in:
Leo Hemsted
2020-07-02 12:12:34 +01:00
parent 3954cd0e4a
commit 7ecd7341b0
12 changed files with 45 additions and 22 deletions

View File

@@ -78,7 +78,8 @@ def dao_update_template_reply_to(template_id, reply_to):
"version": template.version,
"archived": template.archived,
"process_type": template.process_type,
"service_letter_contact_id": template.service_letter_contact_id
"service_letter_contact_id": template.service_letter_contact_id,
"broadcast_data": template.broadcast_data,
})
db.session.add(history)
return template

View File

@@ -26,6 +26,7 @@ from notifications_utils.template import (
PlainTextEmailTemplate,
SMSMessageTemplate,
LetterPrintTemplate,
BroadcastMessageTemplate,
)
from notifications_utils.timezones import convert_utc_to_bst
@@ -44,8 +45,10 @@ from app.history_meta import Versioned
SMS_TYPE = 'sms'
EMAIL_TYPE = 'email'
LETTER_TYPE = 'letter'
BROADCAST_TYPE = 'broadcast'
TEMPLATE_TYPES = [SMS_TYPE, EMAIL_TYPE, LETTER_TYPE]
TEMPLATE_TYPES = [SMS_TYPE, EMAIL_TYPE, LETTER_TYPE, BROADCAST_TYPE]
NOTIFICATION_TYPES = [SMS_TYPE, EMAIL_TYPE, LETTER_TYPE] # not broadcast
template_types = db.Enum(*TEMPLATE_TYPES, name='template_type')
@@ -299,12 +302,12 @@ UPLOAD_DOCUMENT = 'upload_document'
EDIT_FOLDER_PERMISSIONS = 'edit_folder_permissions'
UPLOAD_LETTERS = 'upload_letters'
INTERNATIONAL_LETTERS = 'international_letters'
BROADCAST_TYPE = 'broadcast'
SERVICE_PERMISSION_TYPES = [
EMAIL_TYPE,
SMS_TYPE,
LETTER_TYPE,
BROADCAST_TYPE,
INTERNATIONAL_SMS_TYPE,
INBOUND_SMS_TYPE,
SCHEDULE_NOTIFICATIONS,
@@ -314,7 +317,6 @@ SERVICE_PERMISSION_TYPES = [
EDIT_FOLDER_PERMISSIONS,
UPLOAD_LETTERS,
INTERNATIONAL_LETTERS,
BROADCAST_TYPE,
]
@@ -903,6 +905,7 @@ class TemplateBase(db.Model):
hidden = db.Column(db.Boolean, nullable=False, default=False)
subject = db.Column(db.Text)
postage = db.Column(db.String, nullable=True)
broadcast_data = db.Column(JSONB(none_as_null=True), nullable=True)
@declared_attr
def service_id(cls):
@@ -975,6 +978,8 @@ class TemplateBase(db.Model):
return PlainTextEmailTemplate(self.__dict__)
if self.template_type == SMS_TYPE:
return SMSMessageTemplate(self.__dict__)
if self.template_type == BROADCAST_TYPE:
return BroadcastMessageTemplate(self.__dict__)
if self.template_type == LETTER_TYPE:
return LetterPrintTemplate(
self.__dict__,
@@ -995,7 +1000,7 @@ class TemplateBase(db.Model):
"created_by": self.created_by.email_address,
"version": self.version,
"body": self.content,
"subject": self.subject if self.template_type != SMS_TYPE else None,
"subject": self.subject if self.template_type in {EMAIL_TYPE, LETTER_TYPE} else None,
"name": self.name,
"personalisation": {
key: {
@@ -1004,6 +1009,7 @@ class TemplateBase(db.Model):
for key in self._as_utils_template().placeholders
},
"postage": self.postage,
"broadcast_data": self.broadcast_data
}
return serialized

View File

@@ -365,7 +365,7 @@ class TemplateSchema(BaseTemplateSchema, UUIDsAsStringsMixin):
@validates_schema
def validate_type(self, data):
if data.get('template_type') in [models.EMAIL_TYPE, models.LETTER_TYPE]:
if data.get('template_type') in {models.EMAIL_TYPE, models.LETTER_TYPE}:
subject = data.get('subject')
if not subject or subject.strip() == '':
raise ValidationError('Invalid template subject', 'subject')
@@ -391,6 +391,7 @@ class TemplateSchemaNoDetail(TemplateSchema):
'template_redacted',
'updated_at',
'version',
'broadcast_data',
)

View File

@@ -47,6 +47,7 @@ class SerialisedTemplate(SerialisedModel):
'subject',
'template_type',
'version',
'broadcast_data',
}
@classmethod

View File

@@ -3,7 +3,7 @@ from datetime import datetime
from notifications_utils.timezones import convert_utc_to_bst
from app.models import NOTIFICATION_STATUS_TYPES, TEMPLATE_TYPES
from app.models import NOTIFICATION_STATUS_TYPES, NOTIFICATION_TYPES
from app.dao.date_util import get_months_for_financial_year
@@ -37,7 +37,7 @@ def format_admin_stats(statistics):
def create_stats_dict():
stats_dict = {}
for template in TEMPLATE_TYPES:
for template in NOTIFICATION_TYPES:
stats_dict[template] = {}
for status in ('total', 'test-key'):
@@ -79,7 +79,7 @@ def create_zeroed_stats_dicts():
return {
template_type: {
status: 0 for status in ('requested', 'delivered', 'failed')
} for template_type in TEMPLATE_TYPES
} for template_type in NOTIFICATION_TYPES
}
@@ -100,7 +100,7 @@ def create_empty_monthly_notification_status_stats_dict(year):
return {
convert_utc_to_bst(start).strftime('%Y-%m'): {
template_type: defaultdict(int)
for template_type in TEMPLATE_TYPES
for template_type in NOTIFICATION_TYPES
}
for start in utc_month_starts
}

View File

@@ -4,7 +4,12 @@ import pytz
from flask import url_for
from sqlalchemy import func
from notifications_utils.timezones import convert_utc_to_bst
from notifications_utils.template import SMSMessageTemplate, HTMLEmailTemplate, LetterPrintTemplate
from notifications_utils.template import (
SMSMessageTemplate,
HTMLEmailTemplate,
LetterPrintTemplate,
BroadcastMessageTemplate,
)
local_timezone = pytz.timezone("Europe/London")
@@ -30,9 +35,12 @@ def url_with_token(data, url, config, base_url=None):
def get_template_instance(template, values):
from app.models import SMS_TYPE, EMAIL_TYPE, LETTER_TYPE
from app.models import SMS_TYPE, EMAIL_TYPE, LETTER_TYPE, BROADCAST_TYPE
return {
SMS_TYPE: SMSMessageTemplate, EMAIL_TYPE: HTMLEmailTemplate, LETTER_TYPE: LetterPrintTemplate
SMS_TYPE: SMSMessageTemplate,
EMAIL_TYPE: HTMLEmailTemplate,
LETTER_TYPE: LetterPrintTemplate,
BROADCAST_TYPE: BroadcastMessageTemplate,
}[template['template_type']](template, values)
@@ -70,14 +78,16 @@ def get_london_month_from_utc_column(column):
def get_public_notify_type_text(notify_type, plural=False):
from app.models import (SMS_TYPE, UPLOAD_DOCUMENT, PRECOMPILED_LETTER)
from app.models import (SMS_TYPE, BROADCAST_TYPE, UPLOAD_DOCUMENT, PRECOMPILED_LETTER)
notify_type_text = notify_type
if notify_type == SMS_TYPE:
notify_type_text = 'text message'
if notify_type == UPLOAD_DOCUMENT:
elif notify_type == UPLOAD_DOCUMENT:
notify_type_text = 'document'
if notify_type == PRECOMPILED_LETTER:
elif notify_type == PRECOMPILED_LETTER:
notify_type_text = 'precompiled letter'
elif notify_type == BROADCAST_TYPE:
notify_type_text = 'broadcast message'
return '{}{}'.format(notify_type_text, 's' if plural else '')

View File

@@ -2,7 +2,7 @@ from app.models import (
NOTIFICATION_STATUS_TYPES,
NOTIFICATION_STATUS_LETTER_ACCEPTED,
NOTIFICATION_STATUS_LETTER_RECEIVED,
TEMPLATE_TYPES
NOTIFICATION_TYPES,
)
from app.schema_validation.definitions import (uuid, personalisation)
@@ -83,7 +83,7 @@ get_notifications_request = {
"template_type": {
"type": "array",
"items": {
"enum": TEMPLATE_TYPES
"enum": NOTIFICATION_TYPES
}
},
"include_jobs": {"enum": ["true", "True"]},

View File

@@ -14,6 +14,7 @@ from notifications_utils import SMS_CHAR_COUNT_LIMIT
from app.models import (
BROADCAST_TYPE,
EMAIL_TYPE,
LETTER_TYPE,
SMS_TYPE,
@@ -31,6 +32,7 @@ from tests.conftest import set_config_values
@pytest.mark.parametrize('template_type, subject', [
(BROADCAST_TYPE, None),
(SMS_TYPE, None),
(EMAIL_TYPE, 'subject'),
(LETTER_TYPE, 'subject'),
@@ -529,6 +531,7 @@ def test_should_get_return_all_fields_by_default(
)
assert json_response['data'][0].keys() == {
'archived',
'broadcast_data',
'content',
'created_at',
'created_by',

View File

@@ -3,7 +3,7 @@ import pytest
from flask import json
from app import DATETIME_FORMAT
from app.models import TEMPLATE_TYPES, EMAIL_TYPE, SMS_TYPE, LETTER_TYPE
from app.models import (TEMPLATE_TYPES, EMAIL_TYPE, SMS_TYPE, LETTER_TYPE,)
from tests import create_authorization_header
from tests.app.db import create_template, create_letter_contact
@@ -44,6 +44,7 @@ def test_get_template_by_id_returns_200(
'name': expected_name,
'personalisation': {},
'postage': postage,
'broadcast_data': None,
}
assert json_response == expected_response

View File

@@ -97,7 +97,7 @@ def test_valid_post_template_returns_200(
assert resp_json['id'] == str(template.id)
if tmp_type != SMS_TYPE:
if tmp_type in {EMAIL_TYPE, LETTER_TYPE}:
assert expected_subject in resp_json['subject']
if tmp_type == EMAIL_TYPE:

View File

@@ -112,7 +112,7 @@ def test_get_all_templates_for_invalid_type_returns_400(client, sample_service):
'status_code': 400,
'errors': [
{
'message': 'type coconut is not one of [sms, email, letter]',
'message': 'type coconut is not one of [sms, email, letter, broadcast]',
'error': 'ValidationError'
}
]

View File

@@ -242,7 +242,7 @@ def test_get_all_template_request_schema_against_invalid_args_is_invalid(templat
assert errors['status_code'] == 400
assert len(errors['errors']) == 1
assert errors['errors'][0]['message'] == 'type unknown is not one of [sms, email, letter]'
assert errors['errors'][0]['message'] == 'type unknown is not one of [sms, email, letter, broadcast]'
@pytest.mark.parametrize("response", valid_json_get_all_response)