Move AccountCreationForm to user_authn.
This commit is contained in:
@@ -6,13 +6,10 @@ from __future__ import absolute_import
|
||||
import re
|
||||
from importlib import import_module
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import RegexValidator, slug_re
|
||||
from django.forms import widgets
|
||||
from django.urls import reverse
|
||||
from django.utils.http import int_to_base36
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@@ -28,7 +25,6 @@ from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_f
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
|
||||
from student.message_types import AccountRecovery as AccountRecoveryMessage
|
||||
from student.models import CourseEnrollmentAllowed, email_exists_or_retired
|
||||
from util.password_policy_validators import validate_password
|
||||
|
||||
|
||||
def send_account_recovery_email_for_user(user, request, email=None):
|
||||
@@ -62,242 +58,3 @@ def send_account_recovery_email_for_user(user, request, email=None):
|
||||
user_context=message_context,
|
||||
)
|
||||
ace.send(msg)
|
||||
|
||||
|
||||
class TrueCheckbox(widgets.CheckboxInput):
|
||||
"""
|
||||
A checkbox widget that only accepts "true" (case-insensitive) as true.
|
||||
"""
|
||||
def value_from_datadict(self, data, files, name):
|
||||
value = data.get(name, '')
|
||||
return value.lower() == 'true'
|
||||
|
||||
|
||||
class TrueField(forms.BooleanField):
|
||||
"""
|
||||
A boolean field that only accepts "true" (case-insensitive) as true
|
||||
"""
|
||||
widget = TrueCheckbox
|
||||
|
||||
|
||||
def validate_username(username):
|
||||
"""
|
||||
Verifies a username is valid, raises a ValidationError otherwise.
|
||||
Args:
|
||||
username (unicode): The username to validate.
|
||||
|
||||
This function is configurable with `ENABLE_UNICODE_USERNAME` feature.
|
||||
"""
|
||||
|
||||
username_re = slug_re
|
||||
flags = None
|
||||
message = accounts_settings.USERNAME_INVALID_CHARS_ASCII
|
||||
|
||||
if settings.FEATURES.get("ENABLE_UNICODE_USERNAME"):
|
||||
username_re = r"^{regex}$".format(regex=settings.USERNAME_REGEX_PARTIAL)
|
||||
flags = re.UNICODE
|
||||
message = accounts_settings.USERNAME_INVALID_CHARS_UNICODE
|
||||
|
||||
validator = RegexValidator(
|
||||
regex=username_re,
|
||||
flags=flags,
|
||||
message=message,
|
||||
code='invalid',
|
||||
)
|
||||
|
||||
validator(username)
|
||||
|
||||
|
||||
def contains_html(value):
|
||||
"""
|
||||
Validator method to check whether name contains html tags
|
||||
"""
|
||||
regex = re.compile('(<|>)', re.UNICODE)
|
||||
return bool(regex.search(value))
|
||||
|
||||
|
||||
def validate_name(name):
|
||||
"""
|
||||
Verifies a Full_Name is valid, raises a ValidationError otherwise.
|
||||
Args:
|
||||
name (unicode): The name to validate.
|
||||
"""
|
||||
if contains_html(name):
|
||||
raise forms.ValidationError(_('Full Name cannot contain the following characters: < >'))
|
||||
|
||||
|
||||
class UsernameField(forms.CharField):
|
||||
"""
|
||||
A CharField that validates usernames based on the `ENABLE_UNICODE_USERNAME` feature.
|
||||
"""
|
||||
|
||||
default_validators = [validate_username]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UsernameField, self).__init__(
|
||||
min_length=accounts_settings.USERNAME_MIN_LENGTH,
|
||||
max_length=accounts_settings.USERNAME_MAX_LENGTH,
|
||||
error_messages={
|
||||
"required": accounts_settings.USERNAME_BAD_LENGTH_MSG,
|
||||
"min_length": accounts_settings.USERNAME_BAD_LENGTH_MSG,
|
||||
"max_length": accounts_settings.USERNAME_BAD_LENGTH_MSG,
|
||||
}
|
||||
)
|
||||
|
||||
def clean(self, value):
|
||||
"""
|
||||
Strips the spaces from the username.
|
||||
|
||||
Similar to what `django.forms.SlugField` does.
|
||||
"""
|
||||
|
||||
value = self.to_python(value).strip()
|
||||
return super(UsernameField, self).clean(value)
|
||||
|
||||
|
||||
class AccountCreationForm(forms.Form):
|
||||
"""
|
||||
A form to for account creation data. It is currently only used for
|
||||
validation, not rendering.
|
||||
"""
|
||||
|
||||
_EMAIL_INVALID_MSG = _("A properly formatted e-mail is required")
|
||||
_NAME_TOO_SHORT_MSG = _("Your legal name must be a minimum of one character long")
|
||||
|
||||
# TODO: Resolve repetition
|
||||
|
||||
username = UsernameField()
|
||||
|
||||
email = forms.EmailField(
|
||||
max_length=accounts_settings.EMAIL_MAX_LENGTH,
|
||||
min_length=accounts_settings.EMAIL_MIN_LENGTH,
|
||||
error_messages={
|
||||
"required": _EMAIL_INVALID_MSG,
|
||||
"invalid": _EMAIL_INVALID_MSG,
|
||||
"max_length": _("Email cannot be more than %(limit_value)s characters long"),
|
||||
}
|
||||
)
|
||||
|
||||
password = forms.CharField()
|
||||
|
||||
name = forms.CharField(
|
||||
min_length=accounts_settings.NAME_MIN_LENGTH,
|
||||
error_messages={
|
||||
"required": _NAME_TOO_SHORT_MSG,
|
||||
"min_length": _NAME_TOO_SHORT_MSG,
|
||||
},
|
||||
validators=[validate_name]
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data=None,
|
||||
extra_fields=None,
|
||||
extended_profile_fields=None,
|
||||
do_third_party_auth=True,
|
||||
tos_required=True
|
||||
):
|
||||
super(AccountCreationForm, self).__init__(data)
|
||||
|
||||
extra_fields = extra_fields or {}
|
||||
self.extended_profile_fields = extended_profile_fields or {}
|
||||
self.do_third_party_auth = do_third_party_auth
|
||||
if tos_required:
|
||||
self.fields["terms_of_service"] = TrueField(
|
||||
error_messages={"required": _("You must accept the terms of service.")}
|
||||
)
|
||||
|
||||
# TODO: These messages don't say anything about minimum length
|
||||
error_message_dict = {
|
||||
"level_of_education": _("A level of education is required"),
|
||||
"gender": _("Your gender is required"),
|
||||
"year_of_birth": _("Your year of birth is required"),
|
||||
"mailing_address": _("Your mailing address is required"),
|
||||
"goals": _("A description of your goals is required"),
|
||||
"city": _("A city is required"),
|
||||
"country": _("A country is required")
|
||||
}
|
||||
for field_name, field_value in extra_fields.items():
|
||||
if field_name not in self.fields:
|
||||
if field_name == "honor_code":
|
||||
if field_value == "required":
|
||||
self.fields[field_name] = TrueField(
|
||||
error_messages={
|
||||
"required": _("To enroll, you must follow the honor code.")
|
||||
}
|
||||
)
|
||||
else:
|
||||
required = field_value == "required"
|
||||
min_length = 1 if field_name in ("gender", "level_of_education") else 2
|
||||
error_message = error_message_dict.get(
|
||||
field_name,
|
||||
_("You are missing one or more required fields")
|
||||
)
|
||||
self.fields[field_name] = forms.CharField(
|
||||
required=required,
|
||||
min_length=min_length,
|
||||
error_messages={
|
||||
"required": error_message,
|
||||
"min_length": error_message,
|
||||
}
|
||||
)
|
||||
|
||||
for field in self.extended_profile_fields:
|
||||
if field not in self.fields:
|
||||
self.fields[field] = forms.CharField(required=False)
|
||||
|
||||
def clean_password(self):
|
||||
"""Enforce password policies (if applicable)"""
|
||||
password = self.cleaned_data["password"]
|
||||
if not self.do_third_party_auth:
|
||||
# Creating a temporary user object to test password against username
|
||||
# This user should NOT be saved
|
||||
username = self.cleaned_data.get('username')
|
||||
email = self.cleaned_data.get('email')
|
||||
temp_user = User(username=username, email=email) if username else None
|
||||
validate_password(password, temp_user)
|
||||
return password
|
||||
|
||||
def clean_email(self):
|
||||
""" Enforce email restrictions (if applicable) """
|
||||
email = self.cleaned_data["email"]
|
||||
if settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED is not None:
|
||||
# This Open edX instance has restrictions on what email addresses are allowed.
|
||||
allowed_patterns = settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED
|
||||
# We append a '$' to the regexs to prevent the common mistake of using a
|
||||
# pattern like '.*@edx\\.org' which would match 'bob@edx.org.badguy.com'
|
||||
if not any(re.match(pattern + "$", email) for pattern in allowed_patterns):
|
||||
# This email is not on the whitelist of allowed emails. Check if
|
||||
# they may have been manually invited by an instructor and if not,
|
||||
# reject the registration.
|
||||
if not CourseEnrollmentAllowed.objects.filter(email=email).exists():
|
||||
raise ValidationError(_("Unauthorized email address."))
|
||||
if email_exists_or_retired(email):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"It looks like {email} belongs to an existing account. Try again with a different email address."
|
||||
).format(email=email)
|
||||
)
|
||||
return email
|
||||
|
||||
def clean_year_of_birth(self):
|
||||
"""
|
||||
Parse year_of_birth to an integer, but just use None instead of raising
|
||||
an error if it is malformed
|
||||
"""
|
||||
try:
|
||||
year_str = self.cleaned_data["year_of_birth"]
|
||||
return int(year_str) if year_str is not None else None
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def cleaned_extended_profile(self):
|
||||
"""
|
||||
Return a dictionary containing the extended_profile_fields and values
|
||||
"""
|
||||
return {
|
||||
key: value
|
||||
for key, value in self.cleaned_data.items()
|
||||
if key in self.extended_profile_fields and value is not None
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.core.management.base import BaseCommand
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from six.moves import range
|
||||
|
||||
from student.forms import AccountCreationForm
|
||||
from openedx.core.djangoapps.user_authn.views.registration_form import AccountCreationForm
|
||||
from student.helpers import do_create_account
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ from openedx.core.djangoapps.user_api.models import UserRetirementRequest
|
||||
from openedx.core.djangoapps.user_api.preferences import api as preferences_api
|
||||
from openedx.core.djangoapps.user_authn.message_types import PasswordReset
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from student.forms import AccountCreationForm
|
||||
from student.helpers import DISABLE_UNENROLL_CERT_STATES, cert_info, generate_activation_email_context
|
||||
from student.message_types import AccountActivation, EmailChange, EmailChangeConfirmation, RecoveryEmailCreate
|
||||
from student.models import (
|
||||
|
||||
@@ -8,7 +8,7 @@ from django.forms import CharField, Form
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from student import forms as student_forms
|
||||
from openedx.core.djangoapps.user_authn.views.registration_form import validate_username
|
||||
|
||||
|
||||
class CourseEnrollmentsApiListForm(Form):
|
||||
@@ -46,6 +46,6 @@ class CourseEnrollmentsApiListForm(Form):
|
||||
)
|
||||
)
|
||||
for username in usernames:
|
||||
student_forms.validate_username(username)
|
||||
validate_username(username)
|
||||
return usernames
|
||||
return usernames_csv_string
|
||||
|
||||
@@ -29,8 +29,8 @@ from openedx.core.djangoapps.user_api.errors import (
|
||||
)
|
||||
from openedx.core.djangoapps.user_api.preferences.api import update_user_preferences
|
||||
from openedx.core.lib.api.view_utils import add_serializer_errors
|
||||
from openedx.core.djangoapps.user_authn.views.registration_form import validate_name, validate_username
|
||||
from openedx.features.enterprise_support.utils import get_enterprise_readonly_account_fields
|
||||
from student import forms as student_forms
|
||||
from student import views as student_views
|
||||
from student.models import (
|
||||
AccountRecovery,
|
||||
@@ -245,7 +245,7 @@ def _validate_name_change(user_profile, data, field_errors):
|
||||
|
||||
old_name = user_profile.name
|
||||
try:
|
||||
student_forms.validate_name(data['name'])
|
||||
validate_name(data['name'])
|
||||
except ValidationError as err:
|
||||
field_errors["name"] = {
|
||||
"developer_message": u"Error thrown from validate_name: '{}'".format(err.message),
|
||||
@@ -538,7 +538,7 @@ def _validate_username(username):
|
||||
with override_language('en'):
|
||||
# `validate_username` provides a proper localized message, however the API needs only the English
|
||||
# message by convention.
|
||||
student_forms.validate_username(username)
|
||||
validate_username(username)
|
||||
except (UnicodeError, errors.AccountDataBadType, errors.AccountDataBadLength) as username_err:
|
||||
raise errors.AccountUsernameInvalid(text_type(username_err))
|
||||
except ValidationError as validation_err:
|
||||
|
||||
@@ -19,8 +19,8 @@ from opaque_keys.edx.locator import CourseLocator
|
||||
from lms.djangoapps.verify_student.models import ManualVerification
|
||||
from openedx.core.djangoapps.django_comment_common.models import assign_role
|
||||
from openedx.core.djangoapps.user_authn.utils import generate_password
|
||||
from openedx.core.djangoapps.user_authn.views.registration_form import AccountCreationForm
|
||||
from openedx.features.course_experience import course_home_url_name
|
||||
from student.forms import AccountCreationForm
|
||||
from student.helpers import (
|
||||
AccountValidationError,
|
||||
authenticate_new_user,
|
||||
|
||||
@@ -12,7 +12,7 @@ from django.conf import settings
|
||||
from django.contrib.auth import login as django_login
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied
|
||||
from django.core.validators import ValidationError, validate_email
|
||||
from django.core.validators import ValidationError
|
||||
from django.db import transaction
|
||||
from django.dispatch import Signal
|
||||
from django.http import HttpResponse, HttpResponseForbidden
|
||||
@@ -53,9 +53,10 @@ from openedx.core.djangoapps.user_authn.utils import generate_password
|
||||
from openedx.core.djangoapps.user_api.preferences import api as preferences_api
|
||||
from openedx.core.djangoapps.user_authn.cookies import set_logged_in_cookies
|
||||
from openedx.core.djangoapps.user_authn.views.registration_form import (
|
||||
get_registration_extension_form, RegistrationFormFactory
|
||||
get_registration_extension_form,
|
||||
AccountCreationForm,
|
||||
RegistrationFormFactory
|
||||
)
|
||||
from student.forms import AccountCreationForm
|
||||
from student.helpers import (
|
||||
authenticate_new_user,
|
||||
create_or_set_user_attribute_created_on_site,
|
||||
|
||||
@@ -5,11 +5,16 @@ from __future__ import absolute_import
|
||||
|
||||
import copy
|
||||
from importlib import import_module
|
||||
import re
|
||||
|
||||
import six
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.validators import RegexValidator, ValidationError, slug_re
|
||||
from django.forms import widgets
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django_countries import countries
|
||||
@@ -21,13 +26,257 @@ from openedx.core.djangoapps.user_api import accounts
|
||||
from openedx.core.djangoapps.user_api.helpers import FormDescription
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.features.enterprise_support.api import enterprise_customer_for_request
|
||||
from student.models import UserProfile
|
||||
from student.models import (
|
||||
CourseEnrollmentAllowed,
|
||||
UserProfile,
|
||||
email_exists_or_retired,
|
||||
)
|
||||
from util.password_policy_validators import (
|
||||
password_validators_instruction_texts,
|
||||
password_validators_restrictions
|
||||
password_validators_restrictions,
|
||||
validate_password,
|
||||
)
|
||||
|
||||
|
||||
class TrueCheckbox(widgets.CheckboxInput):
|
||||
"""
|
||||
A checkbox widget that only accepts "true" (case-insensitive) as true.
|
||||
"""
|
||||
def value_from_datadict(self, data, files, name):
|
||||
value = data.get(name, '')
|
||||
return value.lower() == 'true'
|
||||
|
||||
|
||||
class TrueField(forms.BooleanField):
|
||||
"""
|
||||
A boolean field that only accepts "true" (case-insensitive) as true
|
||||
"""
|
||||
widget = TrueCheckbox
|
||||
|
||||
|
||||
def validate_username(username):
|
||||
"""
|
||||
Verifies a username is valid, raises a ValidationError otherwise.
|
||||
Args:
|
||||
username (unicode): The username to validate.
|
||||
|
||||
This function is configurable with `ENABLE_UNICODE_USERNAME` feature.
|
||||
"""
|
||||
|
||||
username_re = slug_re
|
||||
flags = None
|
||||
message = accounts.USERNAME_INVALID_CHARS_ASCII
|
||||
|
||||
if settings.FEATURES.get("ENABLE_UNICODE_USERNAME"):
|
||||
username_re = r"^{regex}$".format(regex=settings.USERNAME_REGEX_PARTIAL)
|
||||
flags = re.UNICODE
|
||||
message = accounts.USERNAME_INVALID_CHARS_UNICODE
|
||||
|
||||
validator = RegexValidator(
|
||||
regex=username_re,
|
||||
flags=flags,
|
||||
message=message,
|
||||
code='invalid',
|
||||
)
|
||||
|
||||
validator(username)
|
||||
|
||||
|
||||
def contains_html(value):
|
||||
"""
|
||||
Validator method to check whether name contains html tags
|
||||
"""
|
||||
regex = re.compile('(<|>)', re.UNICODE)
|
||||
return bool(regex.search(value))
|
||||
|
||||
|
||||
def validate_name(name):
|
||||
"""
|
||||
Verifies a Full_Name is valid, raises a ValidationError otherwise.
|
||||
Args:
|
||||
name (unicode): The name to validate.
|
||||
"""
|
||||
if contains_html(name):
|
||||
raise forms.ValidationError(_('Full Name cannot contain the following characters: < >'))
|
||||
|
||||
|
||||
class UsernameField(forms.CharField):
|
||||
"""
|
||||
A CharField that validates usernames based on the `ENABLE_UNICODE_USERNAME` feature.
|
||||
"""
|
||||
|
||||
default_validators = [validate_username]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UsernameField, self).__init__(
|
||||
min_length=accounts.USERNAME_MIN_LENGTH,
|
||||
max_length=accounts.USERNAME_MAX_LENGTH,
|
||||
error_messages={
|
||||
"required": accounts.USERNAME_BAD_LENGTH_MSG,
|
||||
"min_length": accounts.USERNAME_BAD_LENGTH_MSG,
|
||||
"max_length": accounts.USERNAME_BAD_LENGTH_MSG,
|
||||
}
|
||||
)
|
||||
|
||||
def clean(self, value):
|
||||
"""
|
||||
Strips the spaces from the username.
|
||||
|
||||
Similar to what `django.forms.SlugField` does.
|
||||
"""
|
||||
|
||||
value = self.to_python(value).strip()
|
||||
return super(UsernameField, self).clean(value)
|
||||
|
||||
|
||||
class AccountCreationForm(forms.Form):
|
||||
"""
|
||||
A form to for account creation data. It is currently only used for
|
||||
validation, not rendering.
|
||||
"""
|
||||
|
||||
_EMAIL_INVALID_MSG = _(u"A properly formatted e-mail is required")
|
||||
_NAME_TOO_SHORT_MSG = _(u"Your legal name must be a minimum of one character long")
|
||||
|
||||
# TODO: Resolve repetition
|
||||
|
||||
username = UsernameField()
|
||||
|
||||
email = forms.EmailField(
|
||||
max_length=accounts.EMAIL_MAX_LENGTH,
|
||||
min_length=accounts.EMAIL_MIN_LENGTH,
|
||||
error_messages={
|
||||
"required": _EMAIL_INVALID_MSG,
|
||||
"invalid": _EMAIL_INVALID_MSG,
|
||||
"max_length": _(u"Email cannot be more than %(limit_value)s characters long"),
|
||||
}
|
||||
)
|
||||
|
||||
password = forms.CharField()
|
||||
|
||||
name = forms.CharField(
|
||||
min_length=accounts.NAME_MIN_LENGTH,
|
||||
error_messages={
|
||||
"required": _NAME_TOO_SHORT_MSG,
|
||||
"min_length": _NAME_TOO_SHORT_MSG,
|
||||
},
|
||||
validators=[validate_name]
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data=None,
|
||||
extra_fields=None,
|
||||
extended_profile_fields=None,
|
||||
do_third_party_auth=True,
|
||||
tos_required=True
|
||||
):
|
||||
super(AccountCreationForm, self).__init__(data)
|
||||
|
||||
extra_fields = extra_fields or {}
|
||||
self.extended_profile_fields = extended_profile_fields or {}
|
||||
self.do_third_party_auth = do_third_party_auth
|
||||
if tos_required:
|
||||
self.fields["terms_of_service"] = TrueField(
|
||||
error_messages={"required": _("You must accept the terms of service.")}
|
||||
)
|
||||
|
||||
# TODO: These messages don't say anything about minimum length
|
||||
error_message_dict = {
|
||||
"level_of_education": _("A level of education is required"),
|
||||
"gender": _("Your gender is required"),
|
||||
"year_of_birth": _("Your year of birth is required"),
|
||||
"mailing_address": _("Your mailing address is required"),
|
||||
"goals": _("A description of your goals is required"),
|
||||
"city": _("A city is required"),
|
||||
"country": _("A country is required")
|
||||
}
|
||||
for field_name, field_value in extra_fields.items():
|
||||
if field_name not in self.fields:
|
||||
if field_name == "honor_code":
|
||||
if field_value == "required":
|
||||
self.fields[field_name] = TrueField(
|
||||
error_messages={
|
||||
"required": _("To enroll, you must follow the honor code.")
|
||||
}
|
||||
)
|
||||
else:
|
||||
required = field_value == "required"
|
||||
min_length = 1 if field_name in ("gender", "level_of_education") else 2
|
||||
error_message = error_message_dict.get(
|
||||
field_name,
|
||||
_("You are missing one or more required fields")
|
||||
)
|
||||
self.fields[field_name] = forms.CharField(
|
||||
required=required,
|
||||
min_length=min_length,
|
||||
error_messages={
|
||||
"required": error_message,
|
||||
"min_length": error_message,
|
||||
}
|
||||
)
|
||||
|
||||
for field in self.extended_profile_fields:
|
||||
if field not in self.fields:
|
||||
self.fields[field] = forms.CharField(required=False)
|
||||
|
||||
def clean_password(self):
|
||||
"""Enforce password policies (if applicable)"""
|
||||
password = self.cleaned_data["password"]
|
||||
if not self.do_third_party_auth:
|
||||
# Creating a temporary user object to test password against username
|
||||
# This user should NOT be saved
|
||||
username = self.cleaned_data.get('username')
|
||||
email = self.cleaned_data.get('email')
|
||||
temp_user = User(username=username, email=email) if username else None
|
||||
validate_password(password, temp_user)
|
||||
return password
|
||||
|
||||
def clean_email(self):
|
||||
""" Enforce email restrictions (if applicable) """
|
||||
email = self.cleaned_data["email"]
|
||||
if settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED is not None:
|
||||
# This Open edX instance has restrictions on what email addresses are allowed.
|
||||
allowed_patterns = settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED
|
||||
# We append a '$' to the regexs to prevent the common mistake of using a
|
||||
# pattern like '.*@edx\\.org' which would match 'bob@edx.org.badguy.com'
|
||||
if not any(re.match(pattern + "$", email) for pattern in allowed_patterns):
|
||||
# This email is not on the whitelist of allowed emails. Check if
|
||||
# they may have been manually invited by an instructor and if not,
|
||||
# reject the registration.
|
||||
if not CourseEnrollmentAllowed.objects.filter(email=email).exists():
|
||||
raise ValidationError(_(u"Unauthorized email address."))
|
||||
if email_exists_or_retired(email):
|
||||
raise ValidationError(
|
||||
_(
|
||||
u"It looks like {email} belongs to an existing account. Try again with a different email address."
|
||||
).format(email=email)
|
||||
)
|
||||
return email
|
||||
|
||||
def clean_year_of_birth(self):
|
||||
"""
|
||||
Parse year_of_birth to an integer, but just use None instead of raising
|
||||
an error if it is malformed
|
||||
"""
|
||||
try:
|
||||
year_str = self.cleaned_data["year_of_birth"]
|
||||
return int(year_str) if year_str is not None else None
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def cleaned_extended_profile(self):
|
||||
"""
|
||||
Return a dictionary containing the extended_profile_fields and values
|
||||
"""
|
||||
return {
|
||||
key: value
|
||||
for key, value in self.cleaned_data.items()
|
||||
if key in self.extended_profile_fields and value is not None
|
||||
}
|
||||
|
||||
|
||||
def get_registration_extension_form(*args, **kwargs):
|
||||
"""
|
||||
Convenience function for getting the custom form set in settings.REGISTRATION_EXTENSION_FORM.
|
||||
|
||||
Reference in New Issue
Block a user