mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-09 12:54:14 -05:00
It’s a bit hacky, but it fixes a potential issue for users.
Code adapted from:
2c34f678ab
842 lines
24 KiB
Python
842 lines
24 KiB
Python
import re
|
||
import pytz
|
||
import weakref
|
||
|
||
from flask_wtf import FlaskForm as Form
|
||
from datetime import datetime, timedelta
|
||
from itertools import chain
|
||
|
||
from notifications_utils.recipients import (
|
||
validate_phone_number,
|
||
InvalidPhoneError
|
||
)
|
||
from notifications_utils.columns import Columns
|
||
from wtforms import (
|
||
widgets,
|
||
validators,
|
||
StringField,
|
||
PasswordField,
|
||
ValidationError,
|
||
TextAreaField,
|
||
FileField,
|
||
BooleanField,
|
||
HiddenField,
|
||
IntegerField,
|
||
RadioField,
|
||
FieldList,
|
||
DateField,
|
||
)
|
||
from wtforms.fields.html5 import EmailField, TelField, SearchField
|
||
from wtforms.validators import (DataRequired, Email, Length, Regexp, Optional)
|
||
from flask_wtf.file import FileField as FileField_wtf, FileAllowed
|
||
|
||
from app.main.validators import (Blacklist, CsvFileValidator, ValidGovEmail, NoCommasInPlaceHolders, OnlyGSMCharacters)
|
||
|
||
|
||
def get_time_value_and_label(future_time):
|
||
return (
|
||
future_time.replace(tzinfo=None).isoformat(),
|
||
'{} at {}'.format(
|
||
get_human_day(future_time.astimezone(pytz.timezone('Europe/London'))),
|
||
get_human_time(future_time.astimezone(pytz.timezone('Europe/London')))
|
||
)
|
||
)
|
||
|
||
|
||
def get_human_time(time):
|
||
return {
|
||
'0': 'midnight',
|
||
'12': 'midday'
|
||
}.get(
|
||
time.strftime('%-H'),
|
||
time.strftime('%-I%p').lower()
|
||
)
|
||
|
||
|
||
def get_human_day(time, prefix_today_with='T'):
|
||
# Add 1 hour to get ‘midnight today’ instead of ‘midnight tomorrow’
|
||
time = (time - timedelta(hours=1)).strftime('%A')
|
||
if time == datetime.utcnow().strftime('%A'):
|
||
return '{}oday'.format(prefix_today_with)
|
||
if time == (datetime.utcnow() + timedelta(days=1)).strftime('%A'):
|
||
return 'Tomorrow'
|
||
return time
|
||
|
||
|
||
def get_furthest_possible_scheduled_time():
|
||
return (datetime.utcnow() + timedelta(days=4)).replace(hour=0)
|
||
|
||
|
||
def get_next_hours_until(until):
|
||
now = datetime.utcnow()
|
||
hours = int((until - now).total_seconds() / (60 * 60))
|
||
return [
|
||
(now + timedelta(hours=i)).replace(minute=0, second=0).replace(tzinfo=pytz.utc)
|
||
for i in range(1, hours + 1)
|
||
]
|
||
|
||
|
||
def get_next_days_until(until):
|
||
now = datetime.utcnow()
|
||
days = int((until - now).total_seconds() / (60 * 60 * 24))
|
||
return [
|
||
get_human_day(
|
||
(now + timedelta(days=i)).replace(tzinfo=pytz.utc),
|
||
prefix_today_with='Later t'
|
||
)
|
||
for i in range(0, days + 1)
|
||
]
|
||
|
||
|
||
def email_address(label='Email address', gov_user=True):
|
||
validators = [
|
||
Length(min=5, max=255),
|
||
DataRequired(message='Can’t be empty'),
|
||
Email(message='Enter a valid email address')
|
||
]
|
||
|
||
if gov_user:
|
||
validators.append(ValidGovEmail())
|
||
return EmailField(label, validators)
|
||
|
||
|
||
def strip_whitespace(value):
|
||
if value is not None and hasattr(value, 'strip'):
|
||
return value.strip()
|
||
return value
|
||
|
||
|
||
class UKMobileNumber(TelField):
|
||
def pre_validate(self, form):
|
||
try:
|
||
validate_phone_number(self.data)
|
||
except InvalidPhoneError as e:
|
||
raise ValidationError(str(e))
|
||
|
||
|
||
class InternationalPhoneNumber(TelField):
|
||
def pre_validate(self, form):
|
||
try:
|
||
if self.data:
|
||
validate_phone_number(self.data, international=True)
|
||
except InvalidPhoneError as e:
|
||
raise ValidationError(str(e))
|
||
|
||
|
||
def uk_mobile_number(label='Mobile number'):
|
||
return UKMobileNumber(label,
|
||
validators=[DataRequired(message='Can’t be empty')])
|
||
|
||
|
||
def international_phone_number(label='Mobile number'):
|
||
return InternationalPhoneNumber(
|
||
label,
|
||
validators=[DataRequired(message='Can’t be empty')]
|
||
)
|
||
|
||
|
||
def password(label='Password'):
|
||
return PasswordField(label,
|
||
validators=[DataRequired(message='Can’t be empty'),
|
||
Length(8, 255, message='Must be at least 8 characters'),
|
||
Blacklist(message='Choose a password that’s harder to guess')])
|
||
|
||
|
||
def sms_code():
|
||
verify_code = '^\d{5}$'
|
||
return StringField('Text message code',
|
||
validators=[DataRequired(message='Can’t be empty'),
|
||
Regexp(regex=verify_code,
|
||
message='Code not found')])
|
||
|
||
|
||
def organisation_type():
|
||
return RadioField(
|
||
'Who runs this service?',
|
||
choices=[
|
||
('central', 'Central government'),
|
||
('local', 'Local government'),
|
||
('nhs', 'NHS'),
|
||
],
|
||
validators=[DataRequired()],
|
||
)
|
||
|
||
|
||
class StripWhitespaceForm(Form):
|
||
class Meta:
|
||
def bind_field(self, form, unbound_field, options):
|
||
# FieldList simply doesn't support filters.
|
||
# @see: https://github.com/wtforms/wtforms/issues/148
|
||
no_filter_fields = (FieldList, PasswordField)
|
||
filters = [strip_whitespace] if not issubclass(unbound_field.field_class, no_filter_fields) else []
|
||
filters += unbound_field.kwargs.get('filters', [])
|
||
bound = unbound_field.bind(form=form, filters=filters, **options)
|
||
bound.get_form = weakref.ref(form) # GC won't collect the form if we don't use a weakref
|
||
return bound
|
||
|
||
|
||
class StripWhitespaceStringField(StringField):
|
||
def __init__(self, label=None, **kwargs):
|
||
kwargs['filters'] = tuple(chain(
|
||
kwargs.get('filters', ()),
|
||
(
|
||
strip_whitespace,
|
||
),
|
||
))
|
||
super(StringField, self).__init__(label, **kwargs)
|
||
|
||
|
||
class LoginForm(StripWhitespaceForm):
|
||
email_address = StringField('Email address', validators=[
|
||
Length(min=5, max=255),
|
||
DataRequired(message='Can’t be empty'),
|
||
Email(message='Enter a valid email address')
|
||
])
|
||
password = PasswordField('Password', validators=[
|
||
DataRequired(message='Enter your password')
|
||
])
|
||
|
||
|
||
class RegisterUserForm(StripWhitespaceForm):
|
||
name = StringField('Full name',
|
||
validators=[DataRequired(message='Can’t be empty')])
|
||
email_address = email_address()
|
||
mobile_number = international_phone_number()
|
||
password = password()
|
||
# always register as sms type
|
||
auth_type = HiddenField('auth_type', default='sms_auth')
|
||
|
||
|
||
class RegisterUserFromInviteForm(StripWhitespaceForm):
|
||
def __init__(self, invited_user):
|
||
super().__init__(
|
||
service=invited_user['service'],
|
||
email_address=invited_user['email_address'],
|
||
auth_type=invited_user['auth_type'],
|
||
)
|
||
|
||
name = StringField(
|
||
'Full name',
|
||
validators=[DataRequired(message='Can’t be empty')]
|
||
)
|
||
mobile_number = InternationalPhoneNumber('Mobile number', validators=[])
|
||
password = password()
|
||
service = HiddenField('service')
|
||
email_address = HiddenField('email_address')
|
||
auth_type = HiddenField('auth_type', validators=[DataRequired()])
|
||
|
||
def validate_mobile_number(self, field):
|
||
if self.auth_type.data == 'sms_auth' and not field.data:
|
||
raise ValidationError('Can’t be empty')
|
||
|
||
|
||
class PermissionsForm(StripWhitespaceForm):
|
||
send_messages = BooleanField("Send messages from existing templates")
|
||
manage_templates = BooleanField("Add and edit templates")
|
||
manage_service = BooleanField("Modify this service and its team")
|
||
manage_api_keys = BooleanField("Create and revoke API keys")
|
||
login_authentication = RadioField(
|
||
'Sign in using',
|
||
choices=[
|
||
('sms_auth', 'Text message code'),
|
||
('email_auth', 'Email link'),
|
||
],
|
||
validators=[DataRequired()]
|
||
)
|
||
|
||
|
||
class InviteUserForm(PermissionsForm):
|
||
email_address = email_address(gov_user=False)
|
||
|
||
def __init__(self, invalid_email_address, *args, **kwargs):
|
||
super(InviteUserForm, self).__init__(*args, **kwargs)
|
||
self.invalid_email_address = invalid_email_address.lower()
|
||
|
||
def validate_email_address(self, field):
|
||
if field.data.lower() == self.invalid_email_address:
|
||
raise ValidationError("You can’t send an invitation to yourself")
|
||
|
||
|
||
class TwoFactorForm(StripWhitespaceForm):
|
||
def __init__(self, validate_code_func, *args, **kwargs):
|
||
'''
|
||
Keyword arguments:
|
||
validate_code_func -- Validates the code with the API.
|
||
'''
|
||
self.validate_code_func = validate_code_func
|
||
super(TwoFactorForm, self).__init__(*args, **kwargs)
|
||
|
||
sms_code = sms_code()
|
||
|
||
def validate_sms_code(self, field):
|
||
is_valid, reason = self.validate_code_func(field.data)
|
||
if not is_valid:
|
||
raise ValidationError(reason)
|
||
|
||
|
||
class EmailNotReceivedForm(StripWhitespaceForm):
|
||
email_address = email_address()
|
||
|
||
|
||
class TextNotReceivedForm(StripWhitespaceForm):
|
||
mobile_number = international_phone_number()
|
||
|
||
|
||
class RenameServiceForm(StripWhitespaceForm):
|
||
name = StringField(
|
||
u'Service name',
|
||
validators=[
|
||
DataRequired(message='Can’t be empty')
|
||
])
|
||
|
||
|
||
class CreateServiceForm(StripWhitespaceForm):
|
||
name = StringField(
|
||
u'What’s your service called?',
|
||
validators=[
|
||
DataRequired(message='Can’t be empty')
|
||
])
|
||
organisation_type = organisation_type()
|
||
|
||
|
||
class OrganisationTypeForm(StripWhitespaceForm):
|
||
organisation_type = organisation_type()
|
||
|
||
|
||
class FreeSMSAllowance(StripWhitespaceForm):
|
||
free_sms_allowance = IntegerField(
|
||
'Numbers of text message fragments per year',
|
||
validators=[
|
||
DataRequired(message='Can’t be empty')
|
||
]
|
||
)
|
||
|
||
|
||
class ConfirmPasswordForm(StripWhitespaceForm):
|
||
def __init__(self, validate_password_func, *args, **kwargs):
|
||
self.validate_password_func = validate_password_func
|
||
super(ConfirmPasswordForm, self).__init__(*args, **kwargs)
|
||
|
||
password = PasswordField(u'Enter password')
|
||
|
||
def validate_password(self, field):
|
||
if not self.validate_password_func(field.data):
|
||
raise ValidationError('Invalid password')
|
||
|
||
|
||
class BaseTemplateForm(StripWhitespaceForm):
|
||
name = StringField(
|
||
u'Template name',
|
||
validators=[DataRequired(message="Can’t be empty")])
|
||
|
||
template_content = TextAreaField(
|
||
u'Message',
|
||
validators=[
|
||
DataRequired(message="Can’t be empty"),
|
||
NoCommasInPlaceHolders()
|
||
]
|
||
)
|
||
process_type = RadioField(
|
||
'Use priority queue?',
|
||
choices=[
|
||
('priority', 'Yes'),
|
||
('normal', 'No'),
|
||
],
|
||
validators=[DataRequired()],
|
||
default='normal'
|
||
)
|
||
|
||
|
||
class SMSTemplateForm(BaseTemplateForm):
|
||
def validate_template_content(self, field):
|
||
OnlyGSMCharacters()(None, field)
|
||
|
||
|
||
class EmailTemplateForm(BaseTemplateForm):
|
||
subject = TextAreaField(
|
||
u'Subject',
|
||
validators=[DataRequired(message="Can’t be empty")])
|
||
|
||
|
||
class LetterTemplateForm(EmailTemplateForm):
|
||
|
||
subject = TextAreaField(
|
||
u'Main heading',
|
||
validators=[DataRequired(message="Can’t be empty")])
|
||
|
||
template_content = TextAreaField(
|
||
u'Body',
|
||
validators=[
|
||
DataRequired(message="Can’t be empty"),
|
||
NoCommasInPlaceHolders()
|
||
]
|
||
)
|
||
|
||
|
||
class ForgotPasswordForm(StripWhitespaceForm):
|
||
email_address = email_address(gov_user=False)
|
||
|
||
|
||
class NewPasswordForm(StripWhitespaceForm):
|
||
new_password = password()
|
||
|
||
|
||
class ChangePasswordForm(StripWhitespaceForm):
|
||
def __init__(self, validate_password_func, *args, **kwargs):
|
||
self.validate_password_func = validate_password_func
|
||
super(ChangePasswordForm, self).__init__(*args, **kwargs)
|
||
|
||
old_password = password('Current password')
|
||
new_password = password('New password')
|
||
|
||
def validate_old_password(self, field):
|
||
if not self.validate_password_func(field.data):
|
||
raise ValidationError('Invalid password')
|
||
|
||
|
||
class CsvUploadForm(StripWhitespaceForm):
|
||
file = FileField('Add recipients', validators=[DataRequired(
|
||
message='Please pick a file'), CsvFileValidator()])
|
||
|
||
|
||
class ChangeNameForm(StripWhitespaceForm):
|
||
new_name = StringField(u'Your name')
|
||
|
||
|
||
class ChangeEmailForm(StripWhitespaceForm):
|
||
def __init__(self, validate_email_func, *args, **kwargs):
|
||
self.validate_email_func = validate_email_func
|
||
super(ChangeEmailForm, self).__init__(*args, **kwargs)
|
||
|
||
email_address = email_address()
|
||
|
||
def validate_email_address(self, field):
|
||
is_valid = self.validate_email_func(field.data)
|
||
if not is_valid:
|
||
raise ValidationError("The email address is already in use")
|
||
|
||
|
||
class ChangeMobileNumberForm(StripWhitespaceForm):
|
||
mobile_number = international_phone_number()
|
||
|
||
|
||
class ConfirmMobileNumberForm(StripWhitespaceForm):
|
||
def __init__(self, validate_code_func, *args, **kwargs):
|
||
self.validate_code_func = validate_code_func
|
||
super(ConfirmMobileNumberForm, self).__init__(*args, **kwargs)
|
||
|
||
sms_code = sms_code()
|
||
|
||
def validate_sms_code(self, field):
|
||
is_valid, msg = self.validate_code_func(field.data)
|
||
if not is_valid:
|
||
raise ValidationError(msg)
|
||
|
||
|
||
class ChooseTimeForm(StripWhitespaceForm):
|
||
|
||
def __init__(self, *args, **kwargs):
|
||
super(ChooseTimeForm, self).__init__(*args, **kwargs)
|
||
self.scheduled_for.choices = [('', 'Now')] + [
|
||
get_time_value_and_label(hour) for hour in get_next_hours_until(
|
||
get_furthest_possible_scheduled_time()
|
||
)
|
||
]
|
||
self.scheduled_for.categories = get_next_days_until(get_furthest_possible_scheduled_time())
|
||
|
||
scheduled_for = RadioField(
|
||
'When should Notify send these messages?',
|
||
default='',
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
|
||
class CreateKeyForm(StripWhitespaceForm):
|
||
def __init__(self, existing_key_names=[], *args, **kwargs):
|
||
self.existing_key_names = [x.lower() for x in existing_key_names]
|
||
super(CreateKeyForm, self).__init__(*args, **kwargs)
|
||
|
||
key_type = RadioField(
|
||
'Type of key',
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
key_name = StringField(u'Description of key', validators=[
|
||
DataRequired(message='You need to give the key a name')
|
||
])
|
||
|
||
def validate_key_name(self, key_name):
|
||
if key_name.data.lower() in self.existing_key_names:
|
||
raise ValidationError('A key with this name already exists')
|
||
|
||
|
||
class SupportType(StripWhitespaceForm):
|
||
support_type = RadioField(
|
||
'How can we help you?',
|
||
choices=[
|
||
('report-problem', 'Report a problem'),
|
||
('ask-question-give-feedback', 'Ask a question or give feedback'),
|
||
],
|
||
validators=[DataRequired()]
|
||
)
|
||
|
||
|
||
class Feedback(StripWhitespaceForm):
|
||
name = StringField('Name')
|
||
email_address = StringField('Email address')
|
||
feedback = TextAreaField('Your message', validators=[DataRequired(message="Can’t be empty")])
|
||
|
||
|
||
class Problem(Feedback):
|
||
email_address = email_address(label='Email address', gov_user=False)
|
||
|
||
|
||
class Triage(StripWhitespaceForm):
|
||
severe = RadioField(
|
||
'Is it an emergency?',
|
||
choices=[
|
||
('yes', 'Yes'),
|
||
('no', 'No'),
|
||
],
|
||
validators=[DataRequired()]
|
||
)
|
||
|
||
|
||
class RequestToGoLiveForm(StripWhitespaceForm):
|
||
mou = RadioField(
|
||
(
|
||
'Has your organisation accepted the GOV.UK Notify data sharing and financial '
|
||
'agreement (Memorandum of Understanding)?'
|
||
),
|
||
choices=[
|
||
('yes', 'Yes'),
|
||
('no', 'No'),
|
||
('don’t know', 'I don’t know')
|
||
],
|
||
validators=[DataRequired()]
|
||
)
|
||
channel_email = BooleanField('Emails')
|
||
channel_sms = BooleanField('Text messages')
|
||
channel_letter = BooleanField('Letters')
|
||
start_date = StringField(
|
||
'When will you be ready to start sending messages?',
|
||
validators=[DataRequired(message='Can’t be empty')]
|
||
)
|
||
start_volume = StringField(
|
||
'How many messages do you expect to send to start with?',
|
||
validators=[DataRequired(message='Can’t be empty')]
|
||
)
|
||
peak_volume = StringField(
|
||
'Will the number of messages increase and when will that start?',
|
||
validators=[DataRequired(message='Can’t be empty')]
|
||
)
|
||
upload_or_api = RadioField(
|
||
'How are you going to send messages?',
|
||
choices=[
|
||
('File upload', 'Upload a spreadsheet of recipients'),
|
||
('API', 'Integrate with the GOV.UK Notify API'),
|
||
('API and file upload', 'Both')
|
||
],
|
||
validators=[DataRequired()]
|
||
)
|
||
|
||
|
||
class ProviderForm(StripWhitespaceForm):
|
||
priority = IntegerField('Priority', [validators.NumberRange(min=1, max=100, message="Must be between 1 and 100")])
|
||
|
||
|
||
class ServiceReplyToEmailForm(StripWhitespaceForm):
|
||
email_address = email_address(label='Email reply to address')
|
||
is_default = BooleanField("Make this email address the default")
|
||
|
||
|
||
class ServiceSmsSenderForm(StripWhitespaceForm):
|
||
sms_sender = StringField(
|
||
'Text message sender',
|
||
validators=[
|
||
DataRequired(message="Can’t be empty"),
|
||
Length(max=11, message="Enter 11 characters or fewer")
|
||
]
|
||
)
|
||
is_default = BooleanField("Make this text message sender the default")
|
||
|
||
def validate_sms_sender(self, field):
|
||
if field.data and not re.match(r'^[a-zA-Z0-9\s]+$', field.data):
|
||
raise ValidationError('Use letters and numbers only')
|
||
|
||
|
||
class ServiceEditInboundNumberForm(StripWhitespaceForm):
|
||
is_default = BooleanField("Make this text message sender the default")
|
||
|
||
|
||
class ServiceLetterContactBlockForm(StripWhitespaceForm):
|
||
letter_contact_block = TextAreaField(
|
||
validators=[
|
||
DataRequired(message="Can’t be empty"),
|
||
NoCommasInPlaceHolders()
|
||
]
|
||
)
|
||
is_default = BooleanField("Set as your default address")
|
||
|
||
def validate_letter_contact_block(self, field):
|
||
line_count = field.data.strip().count('\n')
|
||
if line_count >= 10:
|
||
raise ValidationError(
|
||
'Contains {} lines, maximum is 10'.format(line_count + 1)
|
||
)
|
||
|
||
|
||
class ServiceBrandingOrg(StripWhitespaceForm):
|
||
|
||
def __init__(self, organisations=[], *args, **kwargs):
|
||
self.organisation.choices = organisations
|
||
super(ServiceBrandingOrg, self).__init__(*args, **kwargs)
|
||
|
||
branding_type = RadioField(
|
||
'Branding',
|
||
choices=[
|
||
('govuk', 'GOV.UK only'),
|
||
('both', 'GOV.UK and organisation'),
|
||
('org', 'Organisation only'),
|
||
('org_banner', 'Organisation banner')
|
||
],
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
organisation = RadioField(
|
||
'Organisation',
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
|
||
class ServiceSelectOrg(StripWhitespaceForm):
|
||
|
||
def __init__(self, organisations=[], *args, **kwargs):
|
||
self.organisation.choices = organisations
|
||
super(ServiceSelectOrg, self).__init__(*args, **kwargs)
|
||
|
||
organisation = RadioField(
|
||
'Organisation',
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
|
||
class ServiceManageOrg(StripWhitespaceForm):
|
||
|
||
name = StringField('Name')
|
||
|
||
colour = StringField('Colour', render_kw={'onkeyup': 'update_colour_span()', 'onblur': 'update_colour_span()'})
|
||
file = FileField_wtf('Upload a PNG logo', validators=[FileAllowed(['png'], 'PNG Images only!')])
|
||
|
||
|
||
class LetterBranding(StripWhitespaceForm):
|
||
|
||
def __init__(self, choices=[], *args, **kwargs):
|
||
super().__init__(*args, **kwargs)
|
||
self.dvla_org_id.choices = choices
|
||
|
||
dvla_org_id = RadioField(
|
||
'Which logo should this service’s letter have?',
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
|
||
class EmailFieldInWhitelist(EmailField, StripWhitespaceStringField):
|
||
pass
|
||
|
||
|
||
class InternationalPhoneNumberInWhitelist(InternationalPhoneNumber, StripWhitespaceStringField):
|
||
pass
|
||
|
||
|
||
class Whitelist(StripWhitespaceForm):
|
||
|
||
def populate(self, email_addresses, phone_numbers):
|
||
for form_field, existing_whitelist in (
|
||
(self.email_addresses, email_addresses),
|
||
(self.phone_numbers, phone_numbers)
|
||
):
|
||
for index, value in enumerate(existing_whitelist):
|
||
form_field[index].data = value
|
||
|
||
email_addresses = FieldList(
|
||
EmailFieldInWhitelist(
|
||
'',
|
||
validators=[
|
||
Optional(),
|
||
Email(message='Enter valid email addresses')
|
||
],
|
||
default=''
|
||
),
|
||
min_entries=5,
|
||
max_entries=5,
|
||
label="Email addresses"
|
||
)
|
||
|
||
phone_numbers = FieldList(
|
||
InternationalPhoneNumberInWhitelist(
|
||
'',
|
||
validators=[
|
||
Optional()
|
||
],
|
||
default=''
|
||
),
|
||
min_entries=5,
|
||
max_entries=5,
|
||
label="Mobile numbers"
|
||
)
|
||
|
||
|
||
class DateFilterForm(StripWhitespaceForm):
|
||
start_date = DateField("Start Date", [validators.optional()])
|
||
end_date = DateField("End Date", [validators.optional()])
|
||
include_from_test_key = BooleanField("Include test keys", default="checked", false_values={"N"})
|
||
|
||
|
||
class ChooseTemplateType(StripWhitespaceForm):
|
||
|
||
template_type = RadioField(
|
||
'What kind of template do you want to add?',
|
||
validators=[
|
||
DataRequired()
|
||
]
|
||
)
|
||
|
||
def __init__(self, include_letters=False, *args, **kwargs):
|
||
|
||
super().__init__(*args, **kwargs)
|
||
|
||
self.template_type.choices = filter(None, [
|
||
('email', 'Email'),
|
||
('sms', 'Text message'),
|
||
('letter', 'Letter') if include_letters else None
|
||
])
|
||
|
||
|
||
class SearchTemplatesForm(StripWhitespaceForm):
|
||
|
||
search = SearchField('Search by name')
|
||
|
||
|
||
class SearchNotificationsForm(StripWhitespaceForm):
|
||
|
||
to = SearchField('Search by phone number or email address')
|
||
|
||
|
||
class PlaceholderForm(StripWhitespaceForm):
|
||
|
||
pass
|
||
|
||
|
||
class PasswordFieldShowHasContent(StringField):
|
||
widget = widgets.PasswordInput(hide_value=False)
|
||
|
||
|
||
class ServiceInboundNumberForm(StripWhitespaceForm):
|
||
def __init__(self, *args, **kwargs):
|
||
super().__init__(*args, **kwargs)
|
||
self.inbound_number.choices = kwargs['inbound_number_choices']
|
||
|
||
inbound_number = RadioField(
|
||
"Select your inbound number",
|
||
validators=[
|
||
DataRequired("Option must be selected")
|
||
]
|
||
)
|
||
|
||
|
||
class ServiceReceiveMessagesCallbackForm(StripWhitespaceForm):
|
||
url = StringField(
|
||
"URL",
|
||
validators=[DataRequired(message='Can’t be empty'),
|
||
Regexp(regex="^https.*", message='Must be a valid https URL')]
|
||
)
|
||
bearer_token = PasswordFieldShowHasContent(
|
||
"Bearer token",
|
||
validators=[DataRequired(message='Can’t be empty'),
|
||
Length(min=10, message='Must be at least 10 characters')]
|
||
)
|
||
|
||
|
||
class ServiceDeliveryStatusCallbackForm(StripWhitespaceForm):
|
||
url = StringField(
|
||
"URL",
|
||
validators=[DataRequired(message='Can’t be empty'),
|
||
Regexp(regex="^https.*", message='Must be a valid https URL')]
|
||
)
|
||
bearer_token = PasswordFieldShowHasContent(
|
||
"Bearer token",
|
||
validators=[DataRequired(message='Can’t be empty'),
|
||
Length(min=10, message='Must be at least 10 characters')]
|
||
)
|
||
|
||
|
||
class InternationalSMSForm(StripWhitespaceForm):
|
||
enabled = RadioField(
|
||
'Send text messages to international phone numbers',
|
||
choices=[
|
||
('on', 'On'),
|
||
('off', 'Off'),
|
||
],
|
||
)
|
||
|
||
|
||
class SMSPrefixForm(StripWhitespaceForm):
|
||
enabled = RadioField(
|
||
'',
|
||
choices=[
|
||
('on', 'On'),
|
||
('off', 'Off'),
|
||
],
|
||
)
|
||
|
||
|
||
def get_placeholder_form_instance(
|
||
placeholder_name,
|
||
dict_to_populate_from,
|
||
optional_placeholder=False,
|
||
allow_international_phone_numbers=False,
|
||
):
|
||
|
||
if Columns.make_key(placeholder_name) == 'emailaddress':
|
||
field = email_address(label=placeholder_name, gov_user=False)
|
||
elif Columns.make_key(placeholder_name) == 'phonenumber':
|
||
if allow_international_phone_numbers:
|
||
field = international_phone_number(label=placeholder_name)
|
||
else:
|
||
field = uk_mobile_number(label=placeholder_name)
|
||
elif optional_placeholder:
|
||
field = StringField(placeholder_name)
|
||
else:
|
||
field = StringField(placeholder_name, validators=[
|
||
DataRequired(message='Can’t be empty')
|
||
])
|
||
|
||
PlaceholderForm.placeholder_value = field
|
||
|
||
return PlaceholderForm(
|
||
placeholder_value=dict_to_populate_from.get(placeholder_name, '')
|
||
)
|
||
|
||
|
||
class SetSenderForm(StripWhitespaceForm):
|
||
|
||
def __init__(self, *args, **kwargs):
|
||
super().__init__(*args, **kwargs)
|
||
self.sender.choices = kwargs['sender_choices']
|
||
self.sender.label.text = kwargs['sender_label']
|
||
|
||
sender = RadioField()
|