Files
notifications-admin/app/main/forms.py
2016-10-24 12:45:45 +01:00

440 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import pytz
from flask_wtf import Form
from datetime import datetime, timedelta
from notifications_utils.recipients import (
validate_phone_number,
InvalidPhoneError
)
from wtforms import (
validators,
StringField,
PasswordField,
ValidationError,
TextAreaField,
FileField,
BooleanField,
HiddenField,
IntegerField,
RadioField,
FieldList
)
from wtforms.fields.html5 import EmailField, TelField
from wtforms.validators import (DataRequired, Email, Length, Regexp, Optional)
from app.main.validators import (Blacklist, CsvFileValidator, ValidEmailDomainRegex, NoCommasInPlaceHolders)
def get_time_value_and_label(future_time):
return (
future_time.replace(tzinfo=None).isoformat(),
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_next_hours_from(now, hours=23):
return [
(now + timedelta(hours=i)).replace(minute=0, second=0).replace(tzinfo=pytz.utc)
for i in range(1, hours + 1)
]
def email_address(label='Email address'):
return EmailField(label, validators=[
Length(min=5, max=255),
DataRequired(message='Cant be empty'),
Email(message='Enter a valid email address'),
ValidEmailDomainRegex()])
class UKMobileNumber(TelField):
def pre_validate(self, form):
try:
validate_phone_number(self.data)
except InvalidPhoneError as e:
raise ValidationError(e.message)
def mobile_number():
return UKMobileNumber('Mobile number',
validators=[DataRequired(message='Cant be empty')])
def password(label='Password'):
return PasswordField(label,
validators=[DataRequired(message='Cant be empty'),
Length(8, 255, message='Must be at least 8 characters'),
Blacklist(message='Choose a password thats harder to guess')])
def sms_code():
verify_code = '^\d{5}$'
return StringField('Text message code',
validators=[DataRequired(message='Cant be empty'),
Regexp(regex=verify_code,
message='Must be 5 digits')])
def email_code():
verify_code = '^\d{5}$'
return StringField("Email code",
validators=[DataRequired(message='Cant be empty'),
Regexp(regex=verify_code, message='Must be 5 digits')])
class LoginForm(Form):
email_address = StringField('Email address', validators=[
Length(min=5, max=255),
DataRequired(message='Cant be empty'),
Email(message='Enter a valid email address')
])
password = PasswordField('Password', validators=[
DataRequired(message='Enter your password')
])
class RegisterUserForm(Form):
name = StringField('Full name',
validators=[DataRequired(message='Cant be empty')])
email_address = email_address()
mobile_number = mobile_number()
password = password()
class RegisterUserFromInviteForm(Form):
name = StringField('Full name',
validators=[DataRequired(message='Cant be empty')])
mobile_number = mobile_number()
password = password()
service = HiddenField('service')
email_address = HiddenField('email_address')
class PermissionsForm(Form):
send_messages = BooleanField("Send messages from existing templates")
manage_service = BooleanField("Modify this service, its team, and its templates")
manage_api_keys = BooleanField("Create and revoke API keys")
class InviteUserForm(PermissionsForm):
email_address = email_address('Email address')
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 cant send an invitation to yourself")
class TwoFactorForm(Form):
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(Form):
email_address = email_address()
class TextNotReceivedForm(Form):
mobile_number = mobile_number()
class AddServiceForm(Form):
def __init__(self, names_func, *args, **kwargs):
"""
Keyword arguments:
names_func -- Returns a list of unique service_names already registered
on the system.
"""
self._names_func = names_func
super(AddServiceForm, self).__init__(*args, **kwargs)
name = StringField(
'Service name',
validators=[
DataRequired(message='Cant be empty')
]
)
def validate_name(self, a):
from app.utils import email_safe
# make sure the email_from will be unique to all services
if email_safe(a.data) in self._names_func():
raise ValidationError('This service name is already in use')
class ServiceNameForm(Form):
def __init__(self, names_func, *args, **kwargs):
"""
Keyword arguments:
names_func -- Returns a list of unique service_names already registered
on the system.
"""
self._names_func = names_func
super(ServiceNameForm, self).__init__(*args, **kwargs)
name = StringField(
u'Service name',
validators=[
DataRequired(message='Cant be empty')
])
def validate_name(self, a):
from app.utils import email_safe
# make sure the email_from will be unique to all services
if email_safe(a.data) in self._names_func():
raise ValidationError('This service name is already in use')
class ConfirmPasswordForm(Form):
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 SMSTemplateForm(Form):
name = StringField(
u'Template name',
validators=[DataRequired(message="Cant be empty")])
template_content = TextAreaField(
u'Message',
validators=[
DataRequired(message="Cant be empty"),
NoCommasInPlaceHolders()
]
)
class EmailTemplateForm(SMSTemplateForm):
subject = TextAreaField(
u'Subject',
validators=[DataRequired(message="Cant be empty")])
class ForgotPasswordForm(Form):
email_address = email_address()
class NewPasswordForm(Form):
new_password = password()
class ChangePasswordForm(Form):
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(Form):
file = FileField('Add recipients', validators=[DataRequired(
message='Please pick a file'), CsvFileValidator()])
class ChangeNameForm(Form):
new_name = StringField(u'Your name')
class ChangeEmailForm(Form):
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(Form):
mobile_number = mobile_number()
class ConfirmMobileNumberForm(Form):
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(Form):
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_from(datetime.utcnow())
]
scheduled_for = RadioField(
'When should Notify send these messages?',
default='',
validators=[
DataRequired()
]
)
class CreateKeyForm(Form):
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(
'What should Notify do when you use this 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 Feedback(Form):
name = StringField('Name')
email_address = StringField('Email address')
feedback = TextAreaField(u'', validators=[DataRequired(message="Cant be empty")])
class RequestToGoLiveForm(Form):
channel = Stringfield('Are you sending emails or text messages or both?')
start_date = Stringfield('When will you be ready to start sending messages?')
start_volume = Stringfield('How many messages do you expect to send per month to start with? Give an estimate in numbers.')
peak_volume = Stringfield('Will the number of messages a month increase and when will that start? Give an estimate.')
upload_or_api = Stringfield('Are you uploading a list of contacts that youre sending your message to, or are you integrating your system with ours?')
class ProviderForm(Form):
priority = IntegerField('Priority', [validators.NumberRange(min=1, max=100, message="Must be between 1 and 100")])
class ServiceReplyToEmailFrom(Form):
email_address = email_address(label='Email reply to address')
class ServiceSmsSender(Form):
sms_sender = StringField(
'Text message sender',
validators=[
Length(max=11, message="Enter fewer than 11 characters")
]
)
def validate_sms_sender(form, field):
import re
if field.data and not re.match('^[a-zA-Z0-9\s]+$', field.data):
raise ValidationError('Use letters and numbers only')
class ServiceBrandingOrg(Form):
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')
],
validators=[
DataRequired()
]
)
organisation = RadioField(
'Organisation',
validators=[
DataRequired()
]
)
class Whitelist(Form):
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(
EmailField(
'',
validators=[
Optional(),
Email(message='Enter valid email addresses')
],
default=''
),
min_entries=5,
max_entries=5,
label="Email addresses"
)
phone_numbers = FieldList(
UKMobileNumber(
'',
validators=[
Optional()
],
default=''
),
min_entries=5,
max_entries=5,
label="Mobile numbers"
)