Look in all parts of a letter template to find placeholders

Text messages have placeholders in their body.

Emails have them in their subject line too.

Letters have them in their body, subject line and contact block.

We were only looking in the the body and subject when processing a job,
therefore the thing assembling the letter was not looking in all the
CSV columns it needed to, because it hadn’t been told about any
placeholders in the contact block.

Fixing this means always making sure we use the correct `Template`
instance for the type of template we’re dealing with. Which we were
already doing in a different part of the codebase. So it makes sense to
reuse that.

Turns out we fixed the same bug for email subjects over 3 years ago:
3ed97151ee
This commit is contained in:
Chris Hill-Scott
2020-04-06 12:50:22 +01:00
parent e386d2ac38
commit 8c8c8b6328
4 changed files with 89 additions and 35 deletions

View File

@@ -8,10 +8,6 @@ from notifications_utils.recipients import (
RecipientCSV
)
from notifications_utils.statsd_decorators import statsd
from notifications_utils.template import (
SMSMessageTemplate,
WithSubjectTemplate,
)
from notifications_utils.timezones import convert_utc_to_bst
from requests import (
HTTPError,
@@ -128,9 +124,8 @@ def job_complete(job, resumed=False, start=None):
def get_recipient_csv_and_template_and_sender_id(job):
db_template = dao_get_template_by_id(job.template_id, job.template_version)
template = db_template._as_utils_template()
TemplateClass = get_template_class(db_template.template_type)
template = TemplateClass(db_template.__dict__)
contents, meta_data = s3.get_job_and_metadata_from_s3(service_id=str(job.service_id), job_id=str(job.id))
recipient_csv = RecipientCSV(file_data=contents,
template_type=template.template_type,
@@ -454,15 +449,6 @@ def handle_exception(task, notification, notification_id, exc):
current_app.logger.error('Max retry failed' + retry_msg)
def get_template_class(template_type):
if template_type == SMS_TYPE:
return SMSMessageTemplate
elif template_type in (EMAIL_TYPE, LETTER_TYPE):
# since we don't need rendering capabilities (we only need to extract placeholders) both email and letter can
# use the same base template
return WithSubjectTemplate
@notify_celery.task(bind=True, name='update-letter-notifications-statuses')
@statsd(namespace="tasks")
def update_letter_notifications_statuses(self, filename):

View File

@@ -17,7 +17,7 @@ from notifications_utils.statsd_decorators import statsd
from app import db, DATETIME_FORMAT, encryption
from app.aws import s3
from app.celery.tasks import record_daily_sorted_counts, get_template_class, process_row
from app.celery.tasks import record_daily_sorted_counts, process_row
from app.celery.nightly_tasks import send_total_sent_notifications_to_performance_platform
from app.celery.service_callback_tasks import send_delivery_status_to_service
from app.celery.letters_pdf_tasks import create_letters_pdf
@@ -889,8 +889,7 @@ def process_row_from_job(job_id, job_row_number):
job = dao_get_job_by_id(job_id)
db_template = dao_get_template_by_id(job.template_id, job.template_version)
TemplateClass = get_template_class(db_template.template_type)
template = TemplateClass(db_template.__dict__)
template = db_template._as_utils_template()
for row in RecipientCSV(
s3.get_job_from_s3(str(job.service_id), str(job.id)),

View File

@@ -977,16 +977,12 @@ class TemplateBase(db.Model):
def _as_utils_template(self):
if self.template_type == EMAIL_TYPE:
return PlainTextEmailTemplate(
{'content': self.content, 'subject': self.subject}
)
return PlainTextEmailTemplate(self.__dict__)
if self.template_type == SMS_TYPE:
return SMSMessageTemplate(
{'content': self.content}
)
return SMSMessageTemplate(self.__dict__)
if self.template_type == LETTER_TYPE:
return LetterPrintTemplate(
{'content': self.content, 'subject': self.subject},
self.__dict__,
contact_block=self.service.get_default_letter_contact(),
)