mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-23 07:46:23 -04:00
input letter address data in a single block
rather than in multiple placeholders - this is the first step towards making postcodes non-required, which is the first step towards international letters. they still populate address_line_# and postcode fields under the hood - to keep validation working the same, the last line always goes into `postcode`. the form normalises whitespace, removes extra new lines, and enforces that you have between three and seven lines. if the letter repeats address placeholders further down (eg "Dear ((address_line_1))"), then it'll fill those in as well. It'll still prompt you to fill them in, but they'll be pre-filled.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
import weakref
|
||||
from datetime import datetime, timedelta
|
||||
from itertools import chain
|
||||
@@ -9,12 +10,17 @@ from flask_wtf import FlaskForm as Form
|
||||
from flask_wtf.file import FileAllowed
|
||||
from flask_wtf.file import FileField as FileField_wtf
|
||||
from notifications_utils.columns import Columns
|
||||
from notifications_utils.formatters import strip_whitespace
|
||||
from notifications_utils.formatters import (
|
||||
normalise_whitespace_and_newlines,
|
||||
remove_whitespace_before_punctuation,
|
||||
strip_whitespace,
|
||||
)
|
||||
from notifications_utils.recipients import (
|
||||
InvalidPhoneError,
|
||||
normalise_phone_number,
|
||||
validate_phone_number,
|
||||
)
|
||||
from notifications_utils.take import Take
|
||||
from wtforms import (
|
||||
BooleanField,
|
||||
DateField,
|
||||
@@ -362,6 +368,23 @@ class StripWhitespaceStringField(StringField):
|
||||
super(StringField, self).__init__(label, **kwargs)
|
||||
|
||||
|
||||
class StripWhitespaceTextAreaField(TextAreaField):
|
||||
def process_formdata(self, valuelist):
|
||||
if valuelist:
|
||||
self.data = Take(
|
||||
valuelist[0]
|
||||
).then(
|
||||
remove_whitespace_before_punctuation
|
||||
).then(
|
||||
normalise_whitespace_and_newlines
|
||||
).then(
|
||||
# similar to normalise_multiple_newlines but taking everything down to one `\n` instead of two
|
||||
lambda value: re.compile(r'\n{2,}').sub('\n', value)
|
||||
).then(
|
||||
str.strip
|
||||
)
|
||||
|
||||
|
||||
class OnOffField(RadioField):
|
||||
|
||||
def __init__(self, label, choices=None, *args, **kwargs):
|
||||
@@ -741,6 +764,43 @@ class SMSTemplateForm(BaseTemplateForm):
|
||||
OnlySMSCharacters()(None, field)
|
||||
|
||||
|
||||
class LetterAddressForm(StripWhitespaceForm):
|
||||
MIN_ADDRESS_LINES = 3
|
||||
MAX_ADDRESS_LINES = 7
|
||||
|
||||
address = StripWhitespaceTextAreaField(
|
||||
'Address',
|
||||
validators=[DataRequired(message="Cannot be empty")]
|
||||
)
|
||||
|
||||
def validate_address(self, field):
|
||||
lines = field.data.splitlines()
|
||||
if len(lines) < self.MIN_ADDRESS_LINES:
|
||||
raise ValidationError('Address must be at least 3 lines long')
|
||||
if len(lines) > self.MAX_ADDRESS_LINES:
|
||||
raise ValidationError('Address must be no more than 7 lines long')
|
||||
|
||||
@property
|
||||
def as_address_lines_1_to_7_with_postcode(self):
|
||||
lines = self.address.data.splitlines()
|
||||
placeholders = {}
|
||||
|
||||
# set all placeholders to empty strings, or all_placeholders_in_session will always return false.
|
||||
# note that it must be `address line #` with spaces, not underscores or dashes
|
||||
for i in range(1, 7):
|
||||
placeholders[f'address line {i}'] = ''
|
||||
|
||||
# unroll the address into lines, and place into the session in the underlying placeholder names
|
||||
# postcode is required so make sure we put the last value in that
|
||||
# TODO: When postcode is no longer a required field, remove this special case and just use `address line #`
|
||||
address_lines, last_address_line = lines[:-1], lines[-1]
|
||||
for i, line in enumerate(address_lines, start=1):
|
||||
placeholders[f'address line {i}'] = line
|
||||
placeholders['postcode'] = last_address_line
|
||||
|
||||
return placeholders
|
||||
|
||||
|
||||
class EmailTemplateForm(BaseTemplateForm):
|
||||
subject = TextAreaField(
|
||||
u'Subject',
|
||||
|
||||
@@ -39,6 +39,7 @@ from app.main import main, no_cookie
|
||||
from app.main.forms import (
|
||||
ChooseTimeForm,
|
||||
CsvUploadForm,
|
||||
LetterAddressForm,
|
||||
SetSenderForm,
|
||||
get_placeholder_form_instance,
|
||||
)
|
||||
@@ -307,6 +308,11 @@ def send_test(service_id, template_id):
|
||||
return_to='view_template',
|
||||
template_id=template_id))
|
||||
|
||||
if db_template['template_type'] == 'letter':
|
||||
return redirect(
|
||||
url_for('.send_one_off_letter_address', service_id=service_id, template_id=template_id)
|
||||
)
|
||||
|
||||
return redirect(url_for(
|
||||
{
|
||||
'main.send_test': '.send_test_step',
|
||||
@@ -329,6 +335,72 @@ def get_notification_check_endpoint(service_id, template):
|
||||
))
|
||||
|
||||
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/send/<uuid:template_id>/one-off/address",
|
||||
methods=['GET', 'POST']
|
||||
)
|
||||
@user_has_permissions('send_messages', restrict_admin_usage=True)
|
||||
def send_one_off_letter_address(service_id, template_id):
|
||||
if {'recipient', 'placeholders'} - set(session.keys()):
|
||||
# if someone has come here via a bookmark or back button they might have some stuff still in their session
|
||||
return redirect(url_for('.send_one_off', service_id=service_id, template_id=template_id))
|
||||
|
||||
db_template = current_service.get_template_with_user_permission_or_403(template_id, current_user)
|
||||
|
||||
session['send_test_letter_page_count'] = get_page_count_for_letter(db_template)
|
||||
|
||||
template = get_template(
|
||||
db_template,
|
||||
current_service,
|
||||
show_recipient=True,
|
||||
letter_preview_url=url_for(
|
||||
'no_cookie.send_test_preview',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
filetype='png',
|
||||
),
|
||||
page_count=session['send_test_letter_page_count'],
|
||||
email_reply_to=None,
|
||||
sms_sender=None
|
||||
)
|
||||
|
||||
form = LetterAddressForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
session['placeholders'].update(form.as_address_lines_1_to_7_with_postcode)
|
||||
|
||||
placeholders = fields_to_fill_in(
|
||||
template,
|
||||
prefill_current_user=(request.endpoint == 'main.send_test_step'),
|
||||
)
|
||||
if all_placeholders_in_session(placeholders):
|
||||
return get_notification_check_endpoint(service_id, template)
|
||||
|
||||
first_non_address_placeholder_index = len(first_column_headings['letter'])
|
||||
return redirect(url_for(
|
||||
'main.send_one_off_step',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
step_index=first_non_address_placeholder_index,
|
||||
))
|
||||
|
||||
return render_template(
|
||||
'views/send-one-off-letter-address.html',
|
||||
page_title=get_send_test_page_title(
|
||||
template_type='letter',
|
||||
help_argument=None,
|
||||
entering_recipient=True,
|
||||
name=template.name,
|
||||
),
|
||||
template=template,
|
||||
form=form,
|
||||
optional_placeholder=False,
|
||||
back_link=get_back_link(service_id, template, 0),
|
||||
help=False,
|
||||
link_to_upload=True,
|
||||
)
|
||||
|
||||
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/send/<uuid:template_id>/test/step-<int:step_index>",
|
||||
methods=['GET', 'POST'],
|
||||
|
||||
Reference in New Issue
Block a user