diff --git a/common/djangoapps/student/forms.py b/common/djangoapps/student/forms.py
index c980357e98..59264e9626 100644
--- a/common/djangoapps/student/forms.py
+++ b/common/djangoapps/student/forms.py
@@ -387,16 +387,3 @@ class AccountCreationForm(forms.Form):
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.
-
- An example form app for this can be found at http://github.com/open-craft/custom-form-app
- """
- if not getattr(settings, 'REGISTRATION_EXTENSION_FORM', None):
- return None
- module, klass = settings.REGISTRATION_EXTENSION_FORM.rsplit('.', 1)
- module = import_module(module)
- return getattr(module, klass)(*args, **kwargs)
diff --git a/common/djangoapps/student/views/management.py b/common/djangoapps/student/views/management.py
index 711e766d9a..cf8cec36ce 100644
--- a/common/djangoapps/student/views/management.py
+++ b/common/djangoapps/student/views/management.py
@@ -64,7 +64,7 @@ from openedx.core.djangoapps.user_api.errors import UserAPIInternalError, UserNo
from openedx.core.djangoapps.user_api.models import UserRetirementRequest
from openedx.core.djangoapps.user_api.preferences import api as preferences_api
from openedx.core.djangolib.markup import HTML, Text
-from student.forms import AccountCreationForm, PasswordResetFormNoActive, get_registration_extension_form
+from student.forms import AccountCreationForm, PasswordResetFormNoActive
from student.helpers import DISABLE_UNENROLL_CERT_STATES, cert_info, generate_activation_email_context
from student.message_types import EmailChange, EmailChangeConfirmation, PasswordReset, RecoveryEmailCreate
from student.models import (
diff --git a/openedx/core/djangoapps/user_api/api.py b/openedx/core/djangoapps/user_api/api.py
index 2b1d8af70a..4f342516f2 100644
--- a/openedx/core/djangoapps/user_api/api.py
+++ b/openedx/core/djangoapps/user_api/api.py
@@ -20,7 +20,6 @@ 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.forms import get_registration_extension_form
from student.models import UserProfile
from util.password_policy_validators import (
DEFAULT_MAX_PASSWORD_LENGTH,
@@ -161,808 +160,3 @@ def _apply_third_party_auth_overrides(request, form_desc):
"max_length": accounts.EMAIL_MAX_LENGTH,
}
)
-
-
-class RegistrationFormFactory(object):
- """HTTP end-points for creating a new user. """
-
- DEFAULT_FIELDS = ["email", "name", "username", "password"]
-
- EXTRA_FIELDS = [
- "confirm_email",
- "first_name",
- "last_name",
- "city",
- "state",
- "country",
- "gender",
- "year_of_birth",
- "level_of_education",
- "company",
- "job_title",
- "title",
- "mailing_address",
- "goals",
- "honor_code",
- "terms_of_service",
- "profession",
- "specialty",
- ]
-
- def _is_field_visible(self, field_name):
- """Check whether a field is visible based on Django settings. """
- return self._extra_fields_setting.get(field_name) in ["required", "optional"]
-
- def _is_field_required(self, field_name):
- """Check whether a field is required based on Django settings. """
- return self._extra_fields_setting.get(field_name) == "required"
-
- def __init__(self):
-
- # Backwards compatibility: Honor code is required by default, unless
- # explicitly set to "optional" in Django settings.
- self._extra_fields_setting = copy.deepcopy(configuration_helpers.get_value('REGISTRATION_EXTRA_FIELDS'))
- if not self._extra_fields_setting:
- self._extra_fields_setting = copy.deepcopy(settings.REGISTRATION_EXTRA_FIELDS)
- self._extra_fields_setting["honor_code"] = self._extra_fields_setting.get("honor_code", "required")
-
- # Check that the setting is configured correctly
- for field_name in self.EXTRA_FIELDS:
- if self._extra_fields_setting.get(field_name, "hidden") not in ["required", "optional", "hidden"]:
- msg = u"Setting REGISTRATION_EXTRA_FIELDS values must be either required, optional, or hidden."
- raise ImproperlyConfigured(msg)
-
- # Map field names to the instance method used to add the field to the form
- self.field_handlers = {}
- valid_fields = self.DEFAULT_FIELDS + self.EXTRA_FIELDS
- for field_name in valid_fields:
- handler = getattr(self, "_add_{field_name}_field".format(field_name=field_name))
- self.field_handlers[field_name] = handler
-
- field_order = configuration_helpers.get_value('REGISTRATION_FIELD_ORDER')
- if not field_order:
- field_order = settings.REGISTRATION_FIELD_ORDER or valid_fields
-
- # Check that all of the valid_fields are in the field order and vice versa, if not set to the default order
- if set(valid_fields) != set(field_order):
- field_order = valid_fields
-
- self.field_order = field_order
-
- def get_registration_form(self, request):
- """Return a description of the registration form.
- This decouples clients from the API definition:
- if the API decides to modify the form, clients won't need
- to be updated.
- This is especially important for the registration form,
- since different edx-platform installations might
- collect different demographic information.
- See `user_api.helpers.FormDescription` for examples
- of the JSON-encoded form description.
- Arguments:
- request (HttpRequest)
- Returns:
- HttpResponse
- """
- form_desc = FormDescription("post", reverse("user_api_registration"))
- self._apply_third_party_auth_overrides(request, form_desc)
-
- # Custom form fields can be added via the form set in settings.REGISTRATION_EXTENSION_FORM
- custom_form = get_registration_extension_form()
-
- if custom_form:
- # Default fields are always required
- for field_name in self.DEFAULT_FIELDS:
- self.field_handlers[field_name](form_desc, required=True)
-
- for field_name, field in custom_form.fields.items():
- restrictions = {}
- if getattr(field, 'max_length', None):
- restrictions['max_length'] = field.max_length
- if getattr(field, 'min_length', None):
- restrictions['min_length'] = field.min_length
- field_options = getattr(
- getattr(custom_form, 'Meta', None), 'serialization_options', {}
- ).get(field_name, {})
- field_type = field_options.get('field_type', FormDescription.FIELD_TYPE_MAP.get(field.__class__))
- if not field_type:
- raise ImproperlyConfigured(
- u"Field type '{}' not recognized for registration extension field '{}'.".format(
- field_type,
- field_name
- )
- )
- form_desc.add_field(
- field_name, label=field.label,
- default=field_options.get('default'),
- field_type=field_options.get('field_type', FormDescription.FIELD_TYPE_MAP.get(field.__class__)),
- placeholder=field.initial, instructions=field.help_text, required=field.required,
- restrictions=restrictions,
- options=getattr(field, 'choices', None), error_messages=field.error_messages,
- include_default_option=field_options.get('include_default_option'),
- )
-
- # Extra fields configured in Django settings
- # may be required, optional, or hidden
- for field_name in self.EXTRA_FIELDS:
- if self._is_field_visible(field_name):
- self.field_handlers[field_name](
- form_desc,
- required=self._is_field_required(field_name)
- )
- else:
- # Go through the fields in the fields order and add them if they are required or visible
- for field_name in self.field_order:
- if field_name in self.DEFAULT_FIELDS:
- self.field_handlers[field_name](form_desc, required=True)
- elif self._is_field_visible(field_name):
- self.field_handlers[field_name](
- form_desc,
- required=self._is_field_required(field_name)
- )
-
- return form_desc
-
- def _add_email_field(self, form_desc, required=True):
- """Add an email field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # meant to hold the user's email address.
- email_label = _(u"Email")
-
- # Translators: These instructions appear on the registration form, immediately
- # below a field meant to hold the user's email address.
- email_instructions = _(u"This is what you will use to login.")
-
- form_desc.add_field(
- "email",
- field_type="email",
- label=email_label,
- instructions=email_instructions,
- restrictions={
- "min_length": accounts.EMAIL_MIN_LENGTH,
- "max_length": accounts.EMAIL_MAX_LENGTH,
- },
- required=required
- )
-
- def _add_confirm_email_field(self, form_desc, required=True):
- """Add an email confirmation field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # meant to confirm the user's email address.
- email_label = _(u"Confirm Email")
-
- error_msg = accounts.REQUIRED_FIELD_CONFIRM_EMAIL_MSG
-
- form_desc.add_field(
- "confirm_email",
- label=email_label,
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_name_field(self, form_desc, required=True):
- """Add a name field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # meant to hold the user's full name.
- name_label = _(u"Full Name")
-
- # Translators: These instructions appear on the registration form, immediately
- # below a field meant to hold the user's full name.
- name_instructions = _(u"This name will be used on any certificates that you earn.")
-
- form_desc.add_field(
- "name",
- label=name_label,
- instructions=name_instructions,
- restrictions={
- "max_length": accounts.NAME_MAX_LENGTH,
- },
- required=required
- )
-
- def _add_username_field(self, form_desc, required=True):
- """Add a username field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # meant to hold the user's public username.
- username_label = _(u"Public Username")
-
- username_instructions = _(
- # Translators: These instructions appear on the registration form, immediately
- # below a field meant to hold the user's public username.
- u"The name that will identify you in your courses. "
- u"It cannot be changed later."
- )
- form_desc.add_field(
- "username",
- label=username_label,
- instructions=username_instructions,
- restrictions={
- "min_length": accounts.USERNAME_MIN_LENGTH,
- "max_length": accounts.USERNAME_MAX_LENGTH,
- },
- required=required
- )
-
- def _add_password_field(self, form_desc, required=True):
- """Add a password field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # meant to hold the user's password.
- password_label = _(u"Password")
-
- form_desc.add_field(
- "password",
- label=password_label,
- field_type="password",
- instructions=password_validators_instruction_texts(),
- restrictions=password_validators_restrictions(),
- required=required
- )
-
- def _add_level_of_education_field(self, form_desc, required=True):
- """Add a level of education field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a dropdown menu on the registration
- # form used to select the user's highest completed level of education.
- education_level_label = _(u"Highest level of education completed")
- error_msg = accounts.REQUIRED_FIELD_LEVEL_OF_EDUCATION_MSG
-
- # The labels are marked for translation in UserProfile model definition.
- options = [(name, _(label)) for name, label in UserProfile.LEVEL_OF_EDUCATION_CHOICES]
- form_desc.add_field(
- "level_of_education",
- label=education_level_label,
- field_type="select",
- options=options,
- include_default_option=True,
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_gender_field(self, form_desc, required=True):
- """Add a gender field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a dropdown menu on the registration
- # form used to select the user's gender.
- gender_label = _(u"Gender")
-
- # The labels are marked for translation in UserProfile model definition.
- options = [(name, _(label)) for name, label in UserProfile.GENDER_CHOICES]
- form_desc.add_field(
- "gender",
- label=gender_label,
- field_type="select",
- options=options,
- include_default_option=True,
- required=required
- )
-
- def _add_year_of_birth_field(self, form_desc, required=True):
- """Add a year of birth field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a dropdown menu on the registration
- # form used to select the user's year of birth.
- yob_label = _(u"Year of birth")
-
- options = [(six.text_type(year), six.text_type(year)) for year in UserProfile.VALID_YEARS]
- form_desc.add_field(
- "year_of_birth",
- label=yob_label,
- field_type="select",
- options=options,
- include_default_option=True,
- required=required
- )
-
- def _add_field_with_configurable_select_options(self, field_name, field_label, form_desc, required=False):
- """Add a field to a form description.
- If select options are given for this field, it will be a select type
- otherwise it will be a text type.
-
- Arguments:
- field_name: name of field
- field_label: label for the field
- form_desc: A form description
-
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
-
- """
-
- extra_field_options = configuration_helpers.get_value('EXTRA_FIELD_OPTIONS')
- if extra_field_options is None or extra_field_options.get(field_name) is None:
- field_type = "text"
- include_default_option = False
- options = None
- error_msg = ''
- error_msg = getattr(accounts, u'REQUIRED_FIELD_{}_TEXT_MSG'.format(field_name.upper()))
- else:
- field_type = "select"
- include_default_option = True
- field_options = extra_field_options.get(field_name)
- options = [(six.text_type(option.lower()), option) for option in field_options]
- error_msg = ''
- error_msg = getattr(accounts, u'REQUIRED_FIELD_{}_SELECT_MSG'.format(field_name.upper()))
-
- form_desc.add_field(
- field_name,
- label=field_label,
- field_type=field_type,
- options=options,
- include_default_option=include_default_option,
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_profession_field(self, form_desc, required=False):
- """Add a profession field to a form description.
-
- Arguments:
- form_desc: A form description
-
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
-
- """
- # Translators: This label appears above a dropdown menu on the registration
- # form used to select the user's profession
- profession_label = _("Profession")
-
- self._add_field_with_configurable_select_options('profession', profession_label, form_desc, required=required)
-
- def _add_specialty_field(self, form_desc, required=False):
- """Add a specialty field to a form description.
-
- Arguments:
- form_desc: A form description
-
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
-
- """
- # Translators: This label appears above a dropdown menu on the registration
- # form used to select the user's specialty
- specialty_label = _("Specialty")
-
- self._add_field_with_configurable_select_options('specialty', specialty_label, form_desc, required=required)
-
- def _add_mailing_address_field(self, form_desc, required=True):
- """Add a mailing address field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # meant to hold the user's mailing address.
- mailing_address_label = _(u"Mailing address")
- error_msg = accounts.REQUIRED_FIELD_MAILING_ADDRESS_MSG
-
- form_desc.add_field(
- "mailing_address",
- label=mailing_address_label,
- field_type="textarea",
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_goals_field(self, form_desc, required=True):
- """Add a goals field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This phrase appears above a field on the registration form
- # meant to hold the user's reasons for registering with edX.
- goals_label = _(u"Tell us why you're interested in {platform_name}").format(
- platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME)
- )
- error_msg = accounts.REQUIRED_FIELD_GOALS_MSG
-
- form_desc.add_field(
- "goals",
- label=goals_label,
- field_type="textarea",
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_city_field(self, form_desc, required=True):
- """Add a city field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the city in which they live.
- city_label = _(u"City")
- error_msg = accounts.REQUIRED_FIELD_CITY_MSG
-
- form_desc.add_field(
- "city",
- label=city_label,
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_state_field(self, form_desc, required=False):
- """Add a State/Province/Region field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the State/Province/Region in which they live.
- state_label = _(u"State/Province/Region")
-
- form_desc.add_field(
- "state",
- label=state_label,
- required=required
- )
-
- def _add_company_field(self, form_desc, required=False):
- """Add a Company field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the Company
- company_label = _(u"Company")
-
- form_desc.add_field(
- "company",
- label=company_label,
- required=required
- )
-
- def _add_title_field(self, form_desc, required=False):
- """Add a Title field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the Title
- title_label = _(u"Title")
-
- form_desc.add_field(
- "title",
- label=title_label,
- required=required
- )
-
- def _add_job_title_field(self, form_desc, required=False):
- """Add a Job Title field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the Job Title
- job_title_label = _(u"Job Title")
-
- form_desc.add_field(
- "job_title",
- label=job_title_label,
- required=required
- )
-
- def _add_first_name_field(self, form_desc, required=False):
- """Add a First Name field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the First Name
- first_name_label = _(u"First Name")
-
- form_desc.add_field(
- "first_name",
- label=first_name_label,
- required=required
- )
-
- def _add_last_name_field(self, form_desc, required=False):
- """Add a Last Name field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to False
- """
- # Translators: This label appears above a field on the registration form
- # which allows the user to input the First Name
- last_name_label = _(u"Last Name")
-
- form_desc.add_field(
- "last_name",
- label=last_name_label,
- required=required
- )
-
- def _add_country_field(self, form_desc, required=True):
- """Add a country field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This label appears above a dropdown menu on the registration
- # form used to select the country in which the user lives.
- country_label = _(u"Country or Region of Residence")
-
- error_msg = accounts.REQUIRED_FIELD_COUNTRY_MSG
-
- # If we set a country code, make sure it's uppercase for the sake of the form.
- # pylint: disable=protected-access
- default_country = form_desc._field_overrides.get('country', {}).get('defaultValue')
-
- country_instructions = _(
- # Translators: These instructions appear on the registration form, immediately
- # below a field meant to hold the user's country.
- u"The country or region where you live."
- )
- if default_country:
- form_desc.override_field_properties(
- 'country',
- default=default_country.upper()
- )
-
- form_desc.add_field(
- "country",
- label=country_label,
- instructions=country_instructions,
- field_type="select",
- options=list(countries),
- include_default_option=True,
- required=required,
- error_messages={
- "required": error_msg
- }
- )
-
- def _add_honor_code_field(self, form_desc, required=True):
- """Add an honor code field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
-
- separate_honor_and_tos = self._is_field_visible("terms_of_service")
- # Separate terms of service and honor code checkboxes
- if separate_honor_and_tos:
- terms_label = _(u"Honor Code")
- terms_link = marketing_link("HONOR")
-
- # Combine terms of service and honor code checkboxes
- else:
- # Translators: This is a legal document users must agree to
- # in order to register a new account.
- terms_label = _(u"Terms of Service and Honor Code")
- terms_link = marketing_link("HONOR")
-
- # Translators: "Terms of Service" is a legal document users must agree to
- # in order to register a new account.
- label = Text(_(
- u"I agree to the {platform_name} {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end}"
- )).format(
- platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
- terms_of_service=terms_label,
- terms_of_service_link_start=HTML(u"").format(
- terms_link=terms_link
- ),
- terms_of_service_link_end=HTML(""),
- )
-
- # Translators: "Terms of Service" is a legal document users must agree to
- # in order to register a new account.
- error_msg = _(u"You must agree to the {platform_name} {terms_of_service}").format(
- platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
- terms_of_service=terms_label
- )
- field_type = 'checkbox'
-
- if not separate_honor_and_tos:
- current_request = crum.get_current_request()
-
- field_type = 'plaintext'
-
- pp_link = marketing_link("PRIVACY")
- label = Text(_(
- u"By creating an account, you agree to the \
- {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end} \
- and you acknowledge that {platform_name} and each Member process your personal data in accordance \
- with the {privacy_policy_link_start}Privacy Policy{privacy_policy_link_end}."
- )).format(
- platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
- terms_of_service=terms_label,
- terms_of_service_link_start=HTML(u"").format(
- terms_url=terms_link
- ),
- terms_of_service_link_end=HTML(""),
- privacy_policy_link_start=HTML(u"").format(
- pp_url=pp_link
- ),
- privacy_policy_link_end=HTML(""),
- )
-
- form_desc.add_field(
- "honor_code",
- label=label,
- field_type=field_type,
- default=False,
- required=required,
- error_messages={
- "required": error_msg
- },
- )
-
- def _add_terms_of_service_field(self, form_desc, required=True):
- """Add a terms of service field to a form description.
- Arguments:
- form_desc: A form description
- Keyword Arguments:
- required (bool): Whether this field is required; defaults to True
- """
- # Translators: This is a legal document users must agree to
- # in order to register a new account.
- terms_label = _(u"Terms of Service")
- terms_link = marketing_link("TOS")
-
- # Translators: "Terms of service" is a legal document users must agree to
- # in order to register a new account.
- label = Text(_(u"I agree to the {platform_name} {tos_link_start}{terms_of_service}{tos_link_end}")).format(
- platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
- terms_of_service=terms_label,
- tos_link_start=HTML(u"").format(
- terms_link=terms_link
- ),
- tos_link_end=HTML(""),
- )
-
- # Translators: "Terms of service" is a legal document users must agree to
- # in order to register a new account.
- error_msg = _(u"You must agree to the {platform_name} {terms_of_service}").format(
- platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
- terms_of_service=terms_label
- )
-
- form_desc.add_field(
- "terms_of_service",
- label=label,
- field_type="checkbox",
- default=False,
- required=required,
- error_messages={
- "required": error_msg
- },
- )
-
- def _apply_third_party_auth_overrides(self, request, form_desc):
- """Modify the registration form if the user has authenticated with a third-party provider.
- If a user has successfully authenticated with a third-party provider,
- but does not yet have an account with EdX, we want to fill in
- the registration form with any info that we get from the
- provider.
- This will also hide the password field, since we assign users a default
- (random) password on the assumption that they will be using
- third-party auth to log in.
- Arguments:
- request (HttpRequest): The request for the registration form, used
- to determine if the user has successfully authenticated
- with a third-party provider.
- form_desc (FormDescription): The registration form description
- """
- if third_party_auth.is_enabled():
- running_pipeline = third_party_auth.pipeline.get(request)
- if running_pipeline:
- current_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline)
-
- if current_provider:
- # Override username / email / full name
- field_overrides = current_provider.get_register_form_data(
- running_pipeline.get('kwargs')
- )
-
- # When the TPA Provider is configured to skip the registration form and we are in an
- # enterprise context, we need to hide all fields except for terms of service and
- # ensure that the user explicitly checks that field.
- hide_registration_fields_except_tos = (
- (
- current_provider.skip_registration_form and enterprise_customer_for_request(request)
- ) or current_provider.sync_learner_profile_data
- )
-
- for field_name in self.DEFAULT_FIELDS + self.EXTRA_FIELDS:
- if field_name in field_overrides:
- form_desc.override_field_properties(
- field_name, default=field_overrides[field_name]
- )
-
- if (field_name not in ['terms_of_service', 'honor_code']
- and field_overrides[field_name]
- and hide_registration_fields_except_tos):
-
- form_desc.override_field_properties(
- field_name,
- field_type="hidden",
- label="",
- instructions="",
- )
-
- # Hide the password field
- form_desc.override_field_properties(
- "password",
- default="",
- field_type="hidden",
- required=False,
- label="",
- instructions="",
- restrictions={}
- )
- # used to identify that request is running third party social auth
- form_desc.add_field(
- "social_auth_provider",
- field_type="hidden",
- label="",
- default=current_provider.name if current_provider.name else "Third Party",
- required=False,
- )
diff --git a/openedx/core/djangoapps/user_api/views.py b/openedx/core/djangoapps/user_api/views.py
index 08535c3d87..b9bc9212d7 100644
--- a/openedx/core/djangoapps/user_api/views.py
+++ b/openedx/core/djangoapps/user_api/views.py
@@ -25,7 +25,6 @@ from openedx.core.djangoapps.django_comment_common.models import Role
from openedx.core.djangoapps.user_api import accounts
from openedx.core.djangoapps.user_api.accounts.api import check_account_exists
from openedx.core.djangoapps.user_api.api import (
- RegistrationFormFactory,
get_login_session_form,
get_password_reset_form
)
diff --git a/openedx/core/djangoapps/user_authn/views/login_form.py b/openedx/core/djangoapps/user_authn/views/login_form.py
index 0ca063ad67..b19d7d2c4f 100644
--- a/openedx/core/djangoapps/user_authn/views/login_form.py
+++ b/openedx/core/djangoapps/user_authn/views/login_form.py
@@ -19,11 +19,11 @@ from edxmako.shortcuts import render_to_response
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled
from openedx.core.djangoapps.user_api.api import (
- RegistrationFormFactory,
get_login_session_form,
get_password_reset_form
)
from openedx.core.djangoapps.user_authn.cookies import are_logged_in_cookies_set
+from openedx.core.djangoapps.user_authn.views.registration_form import RegistrationFormFactory
from openedx.features.enterprise_support.api import enterprise_customer_for_request
from openedx.features.enterprise_support.utils import (
handle_enterprise_cookies_for_logistration,
diff --git a/openedx/core/djangoapps/user_authn/views/register.py b/openedx/core/djangoapps/user_authn/views/register.py
index fb327ea3ee..44023de5c4 100644
--- a/openedx/core/djangoapps/user_authn/views/register.py
+++ b/openedx/core/djangoapps/user_authn/views/register.py
@@ -36,12 +36,14 @@ from lms.djangoapps.discussion.notification_prefs.views import enable_notificati
from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_api import accounts as accounts_settings
-from openedx.core.djangoapps.user_api.api import RegistrationFormFactory
from openedx.core.djangoapps.user_api.accounts.api import check_account_exists
from openedx.core.djangoapps.user_api.accounts.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 student.forms import AccountCreationForm, get_registration_extension_form
+from openedx.core.djangoapps.user_authn.views.registration_form import (
+ get_registration_extension_form, RegistrationFormFactory
+)
+from student.forms import AccountCreationForm
from student.helpers import (
authenticate_new_user,
create_or_set_user_attribute_created_on_site,
diff --git a/openedx/core/djangoapps/user_authn/views/registration_form.py b/openedx/core/djangoapps/user_authn/views/registration_form.py
new file mode 100644
index 0000000000..d524c7fcfb
--- /dev/null
+++ b/openedx/core/djangoapps/user_authn/views/registration_form.py
@@ -0,0 +1,851 @@
+"""
+Objects and utilities used to construct registration forms.
+"""
+from __future__ import absolute_import
+
+import copy
+from importlib import import_module
+
+import six
+
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.urls import reverse
+from django.utils.translation import ugettext as _
+from django_countries import countries
+
+import third_party_auth
+from edxmako.shortcuts import marketing_link
+from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
+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 util.password_policy_validators import (
+ password_validators_instruction_texts,
+ password_validators_restrictions
+)
+
+
+def get_registration_extension_form(*args, **kwargs):
+ """
+ Convenience function for getting the custom form set in settings.REGISTRATION_EXTENSION_FORM.
+
+ An example form app for this can be found at http://github.com/open-craft/custom-form-app
+ """
+ if not getattr(settings, 'REGISTRATION_EXTENSION_FORM', None):
+ return None
+ module, klass = settings.REGISTRATION_EXTENSION_FORM.rsplit('.', 1)
+ module = import_module(module)
+ return getattr(module, klass)(*args, **kwargs)
+
+
+class RegistrationFormFactory(object):
+ """
+ Construct Registration forms and associated fields.
+ """
+
+ DEFAULT_FIELDS = ["email", "name", "username", "password"]
+
+ EXTRA_FIELDS = [
+ "confirm_email",
+ "first_name",
+ "last_name",
+ "city",
+ "state",
+ "country",
+ "gender",
+ "year_of_birth",
+ "level_of_education",
+ "company",
+ "job_title",
+ "title",
+ "mailing_address",
+ "goals",
+ "honor_code",
+ "terms_of_service",
+ "profession",
+ "specialty",
+ ]
+
+ def _is_field_visible(self, field_name):
+ """Check whether a field is visible based on Django settings. """
+ return self._extra_fields_setting.get(field_name) in ["required", "optional"]
+
+ def _is_field_required(self, field_name):
+ """Check whether a field is required based on Django settings. """
+ return self._extra_fields_setting.get(field_name) == "required"
+
+ def __init__(self):
+
+ # Backwards compatibility: Honor code is required by default, unless
+ # explicitly set to "optional" in Django settings.
+ self._extra_fields_setting = copy.deepcopy(configuration_helpers.get_value('REGISTRATION_EXTRA_FIELDS'))
+ if not self._extra_fields_setting:
+ self._extra_fields_setting = copy.deepcopy(settings.REGISTRATION_EXTRA_FIELDS)
+ self._extra_fields_setting["honor_code"] = self._extra_fields_setting.get("honor_code", "required")
+
+ # Check that the setting is configured correctly
+ for field_name in self.EXTRA_FIELDS:
+ if self._extra_fields_setting.get(field_name, "hidden") not in ["required", "optional", "hidden"]:
+ msg = u"Setting REGISTRATION_EXTRA_FIELDS values must be either required, optional, or hidden."
+ raise ImproperlyConfigured(msg)
+
+ # Map field names to the instance method used to add the field to the form
+ self.field_handlers = {}
+ valid_fields = self.DEFAULT_FIELDS + self.EXTRA_FIELDS
+ for field_name in valid_fields:
+ handler = getattr(self, "_add_{field_name}_field".format(field_name=field_name))
+ self.field_handlers[field_name] = handler
+
+ field_order = configuration_helpers.get_value('REGISTRATION_FIELD_ORDER')
+ if not field_order:
+ field_order = settings.REGISTRATION_FIELD_ORDER or valid_fields
+
+ # Check that all of the valid_fields are in the field order and vice versa, if not set to the default order
+ if set(valid_fields) != set(field_order):
+ field_order = valid_fields
+
+ self.field_order = field_order
+
+ def get_registration_form(self, request):
+ """Return a description of the registration form.
+ This decouples clients from the API definition:
+ if the API decides to modify the form, clients won't need
+ to be updated.
+ This is especially important for the registration form,
+ since different edx-platform installations might
+ collect different demographic information.
+ See `user_api.helpers.FormDescription` for examples
+ of the JSON-encoded form description.
+ Arguments:
+ request (HttpRequest)
+ Returns:
+ HttpResponse
+ """
+ form_desc = FormDescription("post", reverse("user_api_registration"))
+ self._apply_third_party_auth_overrides(request, form_desc)
+
+ # Custom form fields can be added via the form set in settings.REGISTRATION_EXTENSION_FORM
+ custom_form = get_registration_extension_form()
+
+ if custom_form:
+ # Default fields are always required
+ for field_name in self.DEFAULT_FIELDS:
+ self.field_handlers[field_name](form_desc, required=True)
+
+ for field_name, field in custom_form.fields.items():
+ restrictions = {}
+ if getattr(field, 'max_length', None):
+ restrictions['max_length'] = field.max_length
+ if getattr(field, 'min_length', None):
+ restrictions['min_length'] = field.min_length
+ field_options = getattr(
+ getattr(custom_form, 'Meta', None), 'serialization_options', {}
+ ).get(field_name, {})
+ field_type = field_options.get('field_type', FormDescription.FIELD_TYPE_MAP.get(field.__class__))
+ if not field_type:
+ raise ImproperlyConfigured(
+ u"Field type '{}' not recognized for registration extension field '{}'.".format(
+ field_type,
+ field_name
+ )
+ )
+ form_desc.add_field(
+ field_name, label=field.label,
+ default=field_options.get('default'),
+ field_type=field_options.get('field_type', FormDescription.FIELD_TYPE_MAP.get(field.__class__)),
+ placeholder=field.initial, instructions=field.help_text, required=field.required,
+ restrictions=restrictions,
+ options=getattr(field, 'choices', None), error_messages=field.error_messages,
+ include_default_option=field_options.get('include_default_option'),
+ )
+
+ # Extra fields configured in Django settings
+ # may be required, optional, or hidden
+ for field_name in self.EXTRA_FIELDS:
+ if self._is_field_visible(field_name):
+ self.field_handlers[field_name](
+ form_desc,
+ required=self._is_field_required(field_name)
+ )
+ else:
+ # Go through the fields in the fields order and add them if they are required or visible
+ for field_name in self.field_order:
+ if field_name in self.DEFAULT_FIELDS:
+ self.field_handlers[field_name](form_desc, required=True)
+ elif self._is_field_visible(field_name):
+ self.field_handlers[field_name](
+ form_desc,
+ required=self._is_field_required(field_name)
+ )
+
+ return form_desc
+
+ def _add_email_field(self, form_desc, required=True):
+ """Add an email field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # meant to hold the user's email address.
+ email_label = _(u"Email")
+
+ # Translators: These instructions appear on the registration form, immediately
+ # below a field meant to hold the user's email address.
+ email_instructions = _(u"This is what you will use to login.")
+
+ form_desc.add_field(
+ "email",
+ field_type="email",
+ label=email_label,
+ instructions=email_instructions,
+ restrictions={
+ "min_length": accounts.EMAIL_MIN_LENGTH,
+ "max_length": accounts.EMAIL_MAX_LENGTH,
+ },
+ required=required
+ )
+
+ def _add_confirm_email_field(self, form_desc, required=True):
+ """Add an email confirmation field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # meant to confirm the user's email address.
+ email_label = _(u"Confirm Email")
+
+ error_msg = accounts.REQUIRED_FIELD_CONFIRM_EMAIL_MSG
+
+ form_desc.add_field(
+ "confirm_email",
+ label=email_label,
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_name_field(self, form_desc, required=True):
+ """Add a name field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # meant to hold the user's full name.
+ name_label = _(u"Full Name")
+
+ # Translators: These instructions appear on the registration form, immediately
+ # below a field meant to hold the user's full name.
+ name_instructions = _(u"This name will be used on any certificates that you earn.")
+
+ form_desc.add_field(
+ "name",
+ label=name_label,
+ instructions=name_instructions,
+ restrictions={
+ "max_length": accounts.NAME_MAX_LENGTH,
+ },
+ required=required
+ )
+
+ def _add_username_field(self, form_desc, required=True):
+ """Add a username field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # meant to hold the user's public username.
+ username_label = _(u"Public Username")
+
+ username_instructions = _(
+ # Translators: These instructions appear on the registration form, immediately
+ # below a field meant to hold the user's public username.
+ u"The name that will identify you in your courses. "
+ u"It cannot be changed later."
+ )
+ form_desc.add_field(
+ "username",
+ label=username_label,
+ instructions=username_instructions,
+ restrictions={
+ "min_length": accounts.USERNAME_MIN_LENGTH,
+ "max_length": accounts.USERNAME_MAX_LENGTH,
+ },
+ required=required
+ )
+
+ def _add_password_field(self, form_desc, required=True):
+ """Add a password field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # meant to hold the user's password.
+ password_label = _(u"Password")
+
+ form_desc.add_field(
+ "password",
+ label=password_label,
+ field_type="password",
+ instructions=password_validators_instruction_texts(),
+ restrictions=password_validators_restrictions(),
+ required=required
+ )
+
+ def _add_level_of_education_field(self, form_desc, required=True):
+ """Add a level of education field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a dropdown menu on the registration
+ # form used to select the user's highest completed level of education.
+ education_level_label = _(u"Highest level of education completed")
+ error_msg = accounts.REQUIRED_FIELD_LEVEL_OF_EDUCATION_MSG
+
+ # The labels are marked for translation in UserProfile model definition.
+ # pylint: disable=translation-of-non-string
+ options = [(name, _(label)) for name, label in UserProfile.LEVEL_OF_EDUCATION_CHOICES]
+ form_desc.add_field(
+ "level_of_education",
+ label=education_level_label,
+ field_type="select",
+ options=options,
+ include_default_option=True,
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_gender_field(self, form_desc, required=True):
+ """Add a gender field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a dropdown menu on the registration
+ # form used to select the user's gender.
+ gender_label = _(u"Gender")
+
+ # The labels are marked for translation in UserProfile model definition.
+ # pylint: disable=translation-of-non-string
+ options = [(name, _(label)) for name, label in UserProfile.GENDER_CHOICES]
+ form_desc.add_field(
+ "gender",
+ label=gender_label,
+ field_type="select",
+ options=options,
+ include_default_option=True,
+ required=required
+ )
+
+ def _add_year_of_birth_field(self, form_desc, required=True):
+ """Add a year of birth field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a dropdown menu on the registration
+ # form used to select the user's year of birth.
+ yob_label = _(u"Year of birth")
+
+ options = [(six.text_type(year), six.text_type(year)) for year in UserProfile.VALID_YEARS]
+ form_desc.add_field(
+ "year_of_birth",
+ label=yob_label,
+ field_type="select",
+ options=options,
+ include_default_option=True,
+ required=required
+ )
+
+ def _add_field_with_configurable_select_options(self, field_name, field_label, form_desc, required=False):
+ """Add a field to a form description.
+ If select options are given for this field, it will be a select type
+ otherwise it will be a text type.
+
+ Arguments:
+ field_name: name of field
+ field_label: label for the field
+ form_desc: A form description
+
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+
+ """
+
+ extra_field_options = configuration_helpers.get_value('EXTRA_FIELD_OPTIONS')
+ if extra_field_options is None or extra_field_options.get(field_name) is None:
+ field_type = "text"
+ include_default_option = False
+ options = None
+ error_msg = ''
+ error_msg = getattr(accounts, u'REQUIRED_FIELD_{}_TEXT_MSG'.format(field_name.upper()))
+ else:
+ field_type = "select"
+ include_default_option = True
+ field_options = extra_field_options.get(field_name)
+ options = [(six.text_type(option.lower()), option) for option in field_options]
+ error_msg = ''
+ error_msg = getattr(accounts, u'REQUIRED_FIELD_{}_SELECT_MSG'.format(field_name.upper()))
+
+ form_desc.add_field(
+ field_name,
+ label=field_label,
+ field_type=field_type,
+ options=options,
+ include_default_option=include_default_option,
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_profession_field(self, form_desc, required=False):
+ """Add a profession field to a form description.
+
+ Arguments:
+ form_desc: A form description
+
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+
+ """
+ # Translators: This label appears above a dropdown menu on the registration
+ # form used to select the user's profession
+ profession_label = _("Profession")
+
+ self._add_field_with_configurable_select_options('profession', profession_label, form_desc, required=required)
+
+ def _add_specialty_field(self, form_desc, required=False):
+ """Add a specialty field to a form description.
+
+ Arguments:
+ form_desc: A form description
+
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+
+ """
+ # Translators: This label appears above a dropdown menu on the registration
+ # form used to select the user's specialty
+ specialty_label = _("Specialty")
+
+ self._add_field_with_configurable_select_options('specialty', specialty_label, form_desc, required=required)
+
+ def _add_mailing_address_field(self, form_desc, required=True):
+ """Add a mailing address field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # meant to hold the user's mailing address.
+ mailing_address_label = _(u"Mailing address")
+ error_msg = accounts.REQUIRED_FIELD_MAILING_ADDRESS_MSG
+
+ form_desc.add_field(
+ "mailing_address",
+ label=mailing_address_label,
+ field_type="textarea",
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_goals_field(self, form_desc, required=True):
+ """Add a goals field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This phrase appears above a field on the registration form
+ # meant to hold the user's reasons for registering with edX.
+ goals_label = _(u"Tell us why you're interested in {platform_name}").format(
+ platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME)
+ )
+ error_msg = accounts.REQUIRED_FIELD_GOALS_MSG
+
+ form_desc.add_field(
+ "goals",
+ label=goals_label,
+ field_type="textarea",
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_city_field(self, form_desc, required=True):
+ """Add a city field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the city in which they live.
+ city_label = _(u"City")
+ error_msg = accounts.REQUIRED_FIELD_CITY_MSG
+
+ form_desc.add_field(
+ "city",
+ label=city_label,
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_state_field(self, form_desc, required=False):
+ """Add a State/Province/Region field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the State/Province/Region in which they live.
+ state_label = _(u"State/Province/Region")
+
+ form_desc.add_field(
+ "state",
+ label=state_label,
+ required=required
+ )
+
+ def _add_company_field(self, form_desc, required=False):
+ """Add a Company field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the Company
+ company_label = _(u"Company")
+
+ form_desc.add_field(
+ "company",
+ label=company_label,
+ required=required
+ )
+
+ def _add_title_field(self, form_desc, required=False):
+ """Add a Title field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the Title
+ title_label = _(u"Title")
+
+ form_desc.add_field(
+ "title",
+ label=title_label,
+ required=required
+ )
+
+ def _add_job_title_field(self, form_desc, required=False):
+ """Add a Job Title field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the Job Title
+ job_title_label = _(u"Job Title")
+
+ form_desc.add_field(
+ "job_title",
+ label=job_title_label,
+ required=required
+ )
+
+ def _add_first_name_field(self, form_desc, required=False):
+ """Add a First Name field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the First Name
+ first_name_label = _(u"First Name")
+
+ form_desc.add_field(
+ "first_name",
+ label=first_name_label,
+ required=required
+ )
+
+ def _add_last_name_field(self, form_desc, required=False):
+ """Add a Last Name field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to False
+ """
+ # Translators: This label appears above a field on the registration form
+ # which allows the user to input the First Name
+ last_name_label = _(u"Last Name")
+
+ form_desc.add_field(
+ "last_name",
+ label=last_name_label,
+ required=required
+ )
+
+ def _add_country_field(self, form_desc, required=True):
+ """Add a country field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This label appears above a dropdown menu on the registration
+ # form used to select the country in which the user lives.
+ country_label = _(u"Country or Region of Residence")
+
+ error_msg = accounts.REQUIRED_FIELD_COUNTRY_MSG
+
+ # If we set a country code, make sure it's uppercase for the sake of the form.
+ # pylint: disable=protected-access
+ default_country = form_desc._field_overrides.get('country', {}).get('defaultValue')
+
+ country_instructions = _(
+ # Translators: These instructions appear on the registration form, immediately
+ # below a field meant to hold the user's country.
+ u"The country or region where you live."
+ )
+ if default_country:
+ form_desc.override_field_properties(
+ 'country',
+ default=default_country.upper()
+ )
+
+ form_desc.add_field(
+ "country",
+ label=country_label,
+ instructions=country_instructions,
+ field_type="select",
+ options=list(countries),
+ include_default_option=True,
+ required=required,
+ error_messages={
+ "required": error_msg
+ }
+ )
+
+ def _add_honor_code_field(self, form_desc, required=True):
+ """Add an honor code field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+
+ separate_honor_and_tos = self._is_field_visible("terms_of_service")
+ # Separate terms of service and honor code checkboxes
+ if separate_honor_and_tos:
+ terms_label = _(u"Honor Code")
+ terms_link = marketing_link("HONOR")
+
+ # Combine terms of service and honor code checkboxes
+ else:
+ # Translators: This is a legal document users must agree to
+ # in order to register a new account.
+ terms_label = _(u"Terms of Service and Honor Code")
+ terms_link = marketing_link("HONOR")
+
+ # Translators: "Terms of Service" is a legal document users must agree to
+ # in order to register a new account.
+ label = Text(_(
+ u"I agree to the {platform_name} {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end}"
+ )).format(
+ platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
+ terms_of_service=terms_label,
+ terms_of_service_link_start=HTML(u"").format(
+ terms_link=terms_link
+ ),
+ terms_of_service_link_end=HTML(""),
+ )
+
+ # Translators: "Terms of Service" is a legal document users must agree to
+ # in order to register a new account.
+ error_msg = _(u"You must agree to the {platform_name} {terms_of_service}").format(
+ platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
+ terms_of_service=terms_label
+ )
+ field_type = 'checkbox'
+
+ if not separate_honor_and_tos:
+
+ field_type = 'plaintext'
+
+ pp_link = marketing_link("PRIVACY")
+ label = Text(_(
+ u"By creating an account, you agree to the \
+ {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end} \
+ and you acknowledge that {platform_name} and each Member process your personal data in accordance \
+ with the {privacy_policy_link_start}Privacy Policy{privacy_policy_link_end}."
+ )).format(
+ platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
+ terms_of_service=terms_label,
+ terms_of_service_link_start=HTML(u"").format(
+ terms_url=terms_link
+ ),
+ terms_of_service_link_end=HTML(""),
+ privacy_policy_link_start=HTML(u"").format(
+ pp_url=pp_link
+ ),
+ privacy_policy_link_end=HTML(""),
+ )
+
+ form_desc.add_field(
+ "honor_code",
+ label=label,
+ field_type=field_type,
+ default=False,
+ required=required,
+ error_messages={
+ "required": error_msg
+ },
+ )
+
+ def _add_terms_of_service_field(self, form_desc, required=True):
+ """Add a terms of service field to a form description.
+ Arguments:
+ form_desc: A form description
+ Keyword Arguments:
+ required (bool): Whether this field is required; defaults to True
+ """
+ # Translators: This is a legal document users must agree to
+ # in order to register a new account.
+ terms_label = _(u"Terms of Service")
+ terms_link = marketing_link("TOS")
+
+ # Translators: "Terms of service" is a legal document users must agree to
+ # in order to register a new account.
+ label = Text(_(u"I agree to the {platform_name} {tos_link_start}{terms_of_service}{tos_link_end}")).format(
+ platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
+ terms_of_service=terms_label,
+ tos_link_start=HTML(u"").format(
+ terms_link=terms_link
+ ),
+ tos_link_end=HTML(""),
+ )
+
+ # Translators: "Terms of service" is a legal document users must agree to
+ # in order to register a new account.
+ error_msg = _(u"You must agree to the {platform_name} {terms_of_service}").format(
+ platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME),
+ terms_of_service=terms_label
+ )
+
+ form_desc.add_field(
+ "terms_of_service",
+ label=label,
+ field_type="checkbox",
+ default=False,
+ required=required,
+ error_messages={
+ "required": error_msg
+ },
+ )
+
+ def _apply_third_party_auth_overrides(self, request, form_desc):
+ """Modify the registration form if the user has authenticated with a third-party provider.
+ If a user has successfully authenticated with a third-party provider,
+ but does not yet have an account with EdX, we want to fill in
+ the registration form with any info that we get from the
+ provider.
+ This will also hide the password field, since we assign users a default
+ (random) password on the assumption that they will be using
+ third-party auth to log in.
+ Arguments:
+ request (HttpRequest): The request for the registration form, used
+ to determine if the user has successfully authenticated
+ with a third-party provider.
+ form_desc (FormDescription): The registration form description
+ """
+ # pylint: disable=too-many-nested-blocks
+ if third_party_auth.is_enabled():
+ running_pipeline = third_party_auth.pipeline.get(request)
+ if running_pipeline:
+ current_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline)
+
+ if current_provider:
+ # Override username / email / full name
+ field_overrides = current_provider.get_register_form_data(
+ running_pipeline.get('kwargs')
+ )
+
+ # When the TPA Provider is configured to skip the registration form and we are in an
+ # enterprise context, we need to hide all fields except for terms of service and
+ # ensure that the user explicitly checks that field.
+ # pylint: disable=consider-using-ternary
+ hide_registration_fields_except_tos = (
+ (
+ current_provider.skip_registration_form and enterprise_customer_for_request(request)
+ ) or current_provider.sync_learner_profile_data
+ )
+
+ for field_name in self.DEFAULT_FIELDS + self.EXTRA_FIELDS:
+ if field_name in field_overrides:
+ form_desc.override_field_properties(
+ field_name, default=field_overrides[field_name]
+ )
+
+ if (field_name not in ['terms_of_service', 'honor_code']
+ and field_overrides[field_name]
+ and hide_registration_fields_except_tos):
+
+ form_desc.override_field_properties(
+ field_name,
+ field_type="hidden",
+ label="",
+ instructions="",
+ )
+
+ # Hide the password field
+ form_desc.override_field_properties(
+ "password",
+ default="",
+ field_type="hidden",
+ required=False,
+ label="",
+ instructions="",
+ restrictions={}
+ )
+ # used to identify that request is running third party social auth
+ form_desc.add_field(
+ "social_auth_provider",
+ field_type="hidden",
+ label="",
+ default=current_provider.name if current_provider.name else "Third Party",
+ required=False,
+ )
diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_register.py b/openedx/core/djangoapps/user_authn/views/tests/test_register.py
index 5767eefbac..c047793dca 100644
--- a/openedx/core/djangoapps/user_authn/views/tests/test_register.py
+++ b/openedx/core/djangoapps/user_authn/views/tests/test_register.py
@@ -694,7 +694,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
}
)
- @mock.patch('openedx.core.djangoapps.user_api.api._')
+ @mock.patch('openedx.core.djangoapps.user_authn.views.registration_form._')
def test_register_form_level_of_education_translations(self, fake_gettext):
fake_gettext.side_effect = lambda text: text + ' TRANSLATED'
@@ -740,7 +740,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
}
)
- @mock.patch('openedx.core.djangoapps.user_api.api._')
+ @mock.patch('openedx.core.djangoapps.user_authn.views.registration_form._')
def test_register_form_gender_translations(self, fake_gettext):
fake_gettext.side_effect = lambda text: text + ' TRANSLATED'