Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
e6d55294
Commit
e6d55294
authored
Aug 03, 2017
by
tasawernawaz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove Local Server Call on Logistration
LEARNER-966
parent
7c535f5f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
845 additions
and
912 deletions
+845
-912
lms/djangoapps/student_account/views.py
+12
-37
openedx/core/djangoapps/user_api/api.py
+813
-0
openedx/core/djangoapps/user_api/tests/test_views.py
+4
-4
openedx/core/djangoapps/user_api/views.py
+16
-871
No files found.
lms/djangoapps/student_account/views.py
View file @
e6d55294
...
...
@@ -5,13 +5,12 @@ import logging
import
urlparse
from
datetime
import
datetime
import
pytz
from
django.conf
import
settings
from
django.contrib
import
messages
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.decorators
import
login_required
from
django.core.urlresolvers
import
re
solve
,
re
verse
from
django.http
import
HttpRe
quest
,
HttpRe
sponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
from
django.core.urlresolvers
import
reverse
from
django.http
import
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
from
django.shortcuts
import
redirect
from
django.utils.translation
import
ugettext
as
_
from
django.views.decorators.csrf
import
ensure_csrf_cookie
...
...
@@ -20,7 +19,7 @@ from django_countries import countries
import
third_party_auth
from
commerce.models
import
CommerceConfiguration
from
edxmako.shortcuts
import
render_to_response
,
render_to_string
from
edxmako.shortcuts
import
render_to_response
from
lms.djangoapps.commerce.utils
import
EcommerceService
from
openedx.core.djangoapps.commerce.utils
import
ecommerce_api_client
from
openedx.core.djangoapps.external_auth.login_and_register
import
login
as
external_auth_login
...
...
@@ -30,6 +29,11 @@ from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
from
openedx.core.djangoapps.theming.helpers
import
is_request_in_themed_site
from
openedx.core.djangoapps.user_api.accounts.api
import
request_password_change
from
openedx.core.djangoapps.user_api.api
import
(
RegistrationFormFactory
,
get_login_session_form
,
get_password_reset_form
)
from
openedx.core.djangoapps.user_api.errors
import
UserNotFound
from
openedx.core.lib.edx_api_utils
import
get_edx_api_data
from
openedx.core.lib.time_zone_utils
import
TIME_ZONE_CHOICES
...
...
@@ -385,43 +389,14 @@ def _get_form_descriptions(request):
values are the JSON-serialized form descriptions.
"""
return
{
'
login'
:
_local_server_get
(
'/user_api/v1/account/login_session/'
,
request
.
session
),
'
registration'
:
_local_server_get
(
'/user_api/v1/account/registration/'
,
request
.
session
),
'
password_reset'
:
_local_server_get
(
'/user_api/v1/account/password_reset/'
,
request
.
session
)
'
password_reset'
:
get_password_reset_form
()
.
to_json
(
),
'
login'
:
get_login_session_form
()
.
to_json
(
),
'
registration'
:
RegistrationFormFactory
()
.
get_registration_form
(
request
)
.
to_json
(
)
}
def
_local_server_get
(
url
,
session
):
"""Simulate a server-server GET request for an in-process API.
Arguments:
url (str): The URL of the request (excluding the protocol and domain)
session (SessionStore): The session of the original request,
used to get past the CSRF checks.
Returns:
str: The content of the response
"""
# Since the user API is currently run in-process,
# we simulate the server-server API call by constructing
# our own request object. We don't need to include much
# information in the request except for the session
# (to get past through CSRF validation)
request
=
HttpRequest
()
request
.
method
=
"GET"
request
.
session
=
session
# Call the Django view function, simulating
# the server-server API call
view
,
args
,
kwargs
=
resolve
(
url
)
response
=
view
(
request
,
*
args
,
**
kwargs
)
# Return the content of the response
return
response
.
content
def
_external_auth_intercept
(
request
,
mode
):
"""Allow external auth to intercept a login/registration request.
...
...
openedx/core/djangoapps/user_api/api.py
0 → 100644
View file @
e6d55294
import
copy
from
django.conf
import
settings
from
django.core.exceptions
import
ImproperlyConfigured
from
django.core.urlresolvers
import
reverse
from
django.utils.translation
import
ugettext
as
_
from
django_countries
import
countries
import
accounts
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.helpers
import
FormDescription
from
openedx.features.enterprise_support.api
import
enterprise_customer_for_request
from
student.forms
import
get_registration_extension_form
from
student.models
import
UserProfile
def
get_password_reset_form
():
"""Return a description of the password reset form.
This decouples clients from the API definition:
if the API decides to modify the form, clients won't need
to be updated.
See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description.
Returns:
HttpResponse
"""
form_desc
=
FormDescription
(
"post"
,
reverse
(
"password_change_request"
))
# Translators: This label appears above a field on the password reset
# form meant to hold the user's email address.
email_label
=
_
(
u"Email"
)
# Translators: This example email address is used as a placeholder in
# a field on the password reset form meant to hold the user's email address.
email_placeholder
=
_
(
u"username@domain.com"
)
# Translators: These instructions appear on the password reset form,
# immediately below a field meant to hold the user's email address.
email_instructions
=
_
(
u"The email address you used to register with {platform_name}"
)
.
format
(
platform_name
=
configuration_helpers
.
get_value
(
'PLATFORM_NAME'
,
settings
.
PLATFORM_NAME
)
)
form_desc
.
add_field
(
"email"
,
field_type
=
"email"
,
label
=
email_label
,
placeholder
=
email_placeholder
,
instructions
=
email_instructions
,
restrictions
=
{
"min_length"
:
accounts
.
EMAIL_MIN_LENGTH
,
"max_length"
:
accounts
.
EMAIL_MAX_LENGTH
,
}
)
return
form_desc
def
get_login_session_form
():
"""Return a description of the login form.
This decouples clients from the API definition:
if the API decides to modify the form, clients won't need
to be updated.
See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description.
Returns:
HttpResponse
"""
form_desc
=
FormDescription
(
"post"
,
reverse
(
"user_api_login_session"
))
# Translators: This label appears above a field on the login form
# meant to hold the user's email address.
email_label
=
_
(
u"Email"
)
# Translators: This example email address is used as a placeholder in
# a field on the login form meant to hold the user's email address.
email_placeholder
=
_
(
u"username@domain.com"
)
# Translators: These instructions appear on the login form, immediately
# below a field meant to hold the user's email address.
email_instructions
=
_
(
"The email address you used to register with {platform_name}"
)
.
format
(
platform_name
=
configuration_helpers
.
get_value
(
'PLATFORM_NAME'
,
settings
.
PLATFORM_NAME
)
)
form_desc
.
add_field
(
"email"
,
field_type
=
"email"
,
label
=
email_label
,
placeholder
=
email_placeholder
,
instructions
=
email_instructions
,
restrictions
=
{
"min_length"
:
accounts
.
EMAIL_MIN_LENGTH
,
"max_length"
:
accounts
.
EMAIL_MAX_LENGTH
,
}
)
# Translators: This label appears above a field on the login form
# meant to hold the user's password.
password_label
=
_
(
u"Password"
)
form_desc
.
add_field
(
"password"
,
label
=
password_label
,
field_type
=
"password"
,
restrictions
=
{
"max_length"
:
accounts
.
PASSWORD_MAX_LENGTH
,
}
)
form_desc
.
add_field
(
"remember"
,
field_type
=
"checkbox"
,
label
=
_
(
"Remember me"
),
default
=
False
,
required
=
False
,
)
return
form_desc
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"
,
"title"
,
"mailing_address"
,
"goals"
,
"honor_code"
,
"terms_of_service"
,
]
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
(
"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: This example email address is used as a placeholder in
# a field on the registration form meant to hold the user's email address.
email_placeholder
=
_
(
u"username@domain.com"
)
# 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
,
placeholder
=
email_placeholder
,
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: This example name is used as a placeholder in
# a field on the registration form meant to hold the user's name.
name_placeholder
=
_
(
u"Jane Q. Learner"
)
# 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
,
placeholder
=
name_placeholder
,
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."
)
# Translators: This example username is used as a placeholder in
# a field on the registration form meant to hold the user's username.
username_placeholder
=
_
(
u"Jane_Q_Learner"
)
form_desc
.
add_field
(
"username"
,
label
=
username_label
,
instructions
=
username_instructions
,
placeholder
=
username_placeholder
,
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"
,
restrictions
=
{
"min_length"
:
accounts
.
PASSWORD_MIN_LENGTH
,
"max_length"
:
accounts
.
PASSWORD_MAX_LENGTH
,
},
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
]
# pylint: disable=translation-of-non-string
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
]
# pylint: disable=translation-of-non-string
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
=
[(
unicode
(
year
),
unicode
(
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_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_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"
)
error_msg
=
accounts
.
REQUIRED_FIELD_COUNTRY_MSG
# If we set a country code, make sure it's uppercase for the sake of the form.
default_country
=
form_desc
.
_field_overrides
.
get
(
'country'
,
{})
.
get
(
'defaultValue'
)
if
default_country
:
form_desc
.
override_field_properties
(
'country'
,
default
=
default_country
.
upper
()
)
form_desc
.
add_field
(
"country"
,
label
=
country_label
,
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 terms of service and honor code checkboxes
if
self
.
_is_field_visible
(
"terms_of_service"
):
terms_label
=
_
(
u"Honor Code"
)
terms_link
=
marketing_link
(
"HONOR"
)
terms_text
=
_
(
u"Review the Honor Code"
)
# 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"
)
terms_text
=
_
(
u"Review the Terms of Service and Honor Code"
)
# Translators: "Terms of Service" is a legal document users must agree to
# in order to register a new account.
label
=
_
(
u"I 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
)
# 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
(
"honor_code"
,
label
=
label
,
field_type
=
"checkbox"
,
default
=
False
,
required
=
required
,
error_messages
=
{
"required"
:
error_msg
},
supplementalLink
=
terms_link
,
supplementalText
=
terms_text
)
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"
)
terms_text
=
_
(
u"Review the Terms of Service"
)
# Translators: "Terms of service" is a legal document users must agree to
# in order to register a new account.
label
=
_
(
u"I 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
)
# 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
},
supplementalLink
=
terms_link
,
supplementalText
=
terms_text
)
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
))
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
,
)
openedx/core/djangoapps/user_api/tests/test_views.py
View file @
e6d55294
...
...
@@ -609,7 +609,7 @@ class LoginSessionViewTest(UserAPITestCase):
"placeholder"
:
""
,
"instructions"
:
""
,
"restrictions"
:
{
"max_length"
:
PASSWORD_MAX_LENGTH
"max_length"
:
PASSWORD_MAX_LENGTH
,
},
"errorMessages"
:
{},
"supplementalText"
:
""
,
...
...
@@ -1098,7 +1098,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
provider
=
self
.
configure_google_provider
(
enabled
=
True
)
with
simulate_running_pipeline
(
"openedx.core.djangoapps.user_api.
views
.third_party_auth.pipeline"
,
"google-oauth2"
,
"openedx.core.djangoapps.user_api.
api
.third_party_auth.pipeline"
,
"google-oauth2"
,
email
=
"bob@example.com"
,
fullname
=
"Bob"
,
username
=
"Bob123"
,
...
...
@@ -1203,7 +1203,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
}
)
@mock.patch
(
'openedx.core.djangoapps.user_api.
views
._'
)
@mock.patch
(
'openedx.core.djangoapps.user_api.
api
._'
)
def
test_register_form_level_of_education_translations
(
self
,
fake_gettext
):
fake_gettext
.
side_effect
=
lambda
text
:
text
+
' TRANSLATED'
...
...
@@ -1249,7 +1249,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
}
)
@mock.patch
(
'openedx.core.djangoapps.user_api.
views
._'
)
@mock.patch
(
'openedx.core.djangoapps.user_api.
api
._'
)
def
test_register_form_gender_translations
(
self
,
fake_gettext
):
fake_gettext
.
side_effect
=
lambda
text
:
text
+
' TRANSLATED'
...
...
openedx/core/djangoapps/user_api/views.py
View file @
e6d55294
"""HTTP end-points for the User API. """
import
copy
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
from
django.core.exceptions
import
NON_FIELD_ERRORS
,
ImproperlyConfigured
,
PermissionDenied
,
ValidationError
from
django.core.urlresolvers
import
reverse
from
django.core.exceptions
import
NON_FIELD_ERRORS
,
PermissionDenied
,
ValidationError
from
django.http
import
HttpResponse
,
HttpResponseForbidden
from
django.utils.decorators
import
method_decorator
from
django.utils.translation
import
ugettext
as
_
from
django.views.decorators.csrf
import
csrf_exempt
,
csrf_protect
,
ensure_csrf_cookie
from
django.views.decorators.debug
import
sensitive_post_parameters
from
django_countries
import
countries
from
django_filters.rest_framework
import
DjangoFilterBackend
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx
import
locator
...
...
@@ -19,25 +15,24 @@ from rest_framework import authentication, generics, status, viewsets
from
rest_framework.exceptions
import
ParseError
from
rest_framework.views
import
APIView
import
third_party_auth
import
accounts
from
django_comment_common.models
import
Role
from
edxmako.shortcuts
import
marketing_link
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
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
)
from
openedx.core.djangoapps.user_api.helpers
import
require_post_params
,
shim_student_view
from
openedx.core.djangoapps.user_api.models
import
UserPreference
from
openedx.core.djangoapps.user_api.preferences.api
import
get_country_time_zones
,
update_email_opt_in
from
openedx.core.djangoapps.user_api.serializers
import
CountryTimeZoneSerializer
,
UserPreferenceSerializer
,
UserSerializer
from
openedx.core.lib.api.authentication
import
SessionAuthenticationAllowInactiveUser
from
openedx.core.lib.api.permissions
import
ApiKeyHeaderPermission
from
openedx.features.enterprise_support.api
import
enterprise_customer_for_request
from
student.cookies
import
set_logged_in_cookies
from
student.forms
import
get_registration_extension_form
from
student.views
import
create_account_with_params
,
AccountValidationError
from
student.views
import
AccountValidationError
,
create_account_with_params
from
util.json_request
import
JsonResponse
import
accounts
from
.helpers
import
FormDescription
,
require_post_params
,
shim_student_view
from
.models
import
UserPreference
,
UserProfile
from
.preferences.api
import
get_country_time_zones
,
update_email_opt_in
from
.serializers
import
CountryTimeZoneSerializer
,
UserPreferenceSerializer
,
UserSerializer
class
LoginSessionView
(
APIView
):
"""HTTP end-points for logging in users. """
...
...
@@ -48,69 +43,7 @@ class LoginSessionView(APIView):
@method_decorator
(
ensure_csrf_cookie
)
def
get
(
self
,
request
):
"""Return a description of the login form.
This decouples clients from the API definition:
if the API decides to modify the form, clients won't need
to be updated.
See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description.
Returns:
HttpResponse
"""
form_desc
=
FormDescription
(
"post"
,
reverse
(
"user_api_login_session"
))
# Translators: This label appears above a field on the login form
# meant to hold the user's email address.
email_label
=
_
(
u"Email"
)
# Translators: This example email address is used as a placeholder in
# a field on the login form meant to hold the user's email address.
email_placeholder
=
_
(
u"username@domain.com"
)
# Translators: These instructions appear on the login form, immediately
# below a field meant to hold the user's email address.
email_instructions
=
_
(
"The email address you used to register with {platform_name}"
)
.
format
(
platform_name
=
configuration_helpers
.
get_value
(
'PLATFORM_NAME'
,
settings
.
PLATFORM_NAME
)
)
form_desc
.
add_field
(
"email"
,
field_type
=
"email"
,
label
=
email_label
,
placeholder
=
email_placeholder
,
instructions
=
email_instructions
,
restrictions
=
{
"min_length"
:
accounts
.
EMAIL_MIN_LENGTH
,
"max_length"
:
accounts
.
EMAIL_MAX_LENGTH
,
}
)
# Translators: This label appears above a field on the login form
# meant to hold the user's password.
password_label
=
_
(
u"Password"
)
form_desc
.
add_field
(
"password"
,
label
=
password_label
,
field_type
=
"password"
,
restrictions
=
{
"max_length"
:
accounts
.
PASSWORD_MAX_LENGTH
,
}
)
form_desc
.
add_field
(
"remember"
,
field_type
=
"checkbox"
,
label
=
_
(
"Remember me"
),
default
=
False
,
required
=
False
,
)
return
HttpResponse
(
form_desc
.
to_json
(),
content_type
=
"application/json"
)
return
HttpResponse
(
get_login_session_form
()
.
to_json
(),
content_type
=
"application/json"
)
@method_decorator
(
require_post_params
([
"email"
,
"password"
]))
@method_decorator
(
csrf_protect
)
...
...
@@ -157,151 +90,14 @@ class LoginSessionView(APIView):
class
RegistrationView
(
APIView
):
"""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"
,
"title"
,
"mailing_address"
,
"goals"
,
"honor_code"
,
"terms_of_service"
,
]
# This end-point is available to anonymous users,
# so do not require authentication.
authentication_classes
=
[]
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
,
*
args
,
**
kwargs
):
super
(
RegistrationView
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
# 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
@method_decorator
(
ensure_csrf_cookie
)
def
get
(
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
(
"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
HttpResponse
(
form_desc
.
to_json
(),
content_type
=
"application/json"
)
return
HttpResponse
(
RegistrationFormFactory
()
.
get_registration_form
(
request
)
.
to_json
(),
content_type
=
"application/json"
)
@method_decorator
(
csrf_exempt
)
def
post
(
self
,
request
):
...
...
@@ -377,616 +173,6 @@ class RegistrationView(APIView):
def
dispatch
(
self
,
request
,
*
args
,
**
kwargs
):
return
super
(
RegistrationView
,
self
)
.
dispatch
(
request
,
*
args
,
**
kwargs
)
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: This example email address is used as a placeholder in
# a field on the registration form meant to hold the user's email address.
email_placeholder
=
_
(
u"username@domain.com"
)
# 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
,
placeholder
=
email_placeholder
,
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: This example name is used as a placeholder in
# a field on the registration form meant to hold the user's name.
name_placeholder
=
_
(
u"Jane Q. Learner"
)
# 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
,
placeholder
=
name_placeholder
,
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."
)
# Translators: This example username is used as a placeholder in
# a field on the registration form meant to hold the user's username.
username_placeholder
=
_
(
u"Jane_Q_Learner"
)
form_desc
.
add_field
(
"username"
,
label
=
username_label
,
instructions
=
username_instructions
,
placeholder
=
username_placeholder
,
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"
,
restrictions
=
{
"min_length"
:
accounts
.
PASSWORD_MIN_LENGTH
,
"max_length"
:
accounts
.
PASSWORD_MAX_LENGTH
,
},
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
]
# pylint: disable=translation-of-non-string
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
]
# pylint: disable=translation-of-non-string
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
=
[(
unicode
(
year
),
unicode
(
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_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_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"
)
error_msg
=
accounts
.
REQUIRED_FIELD_COUNTRY_MSG
# If we set a country code, make sure it's uppercase for the sake of the form.
default_country
=
form_desc
.
_field_overrides
.
get
(
'country'
,
{})
.
get
(
'defaultValue'
)
if
default_country
:
form_desc
.
override_field_properties
(
'country'
,
default
=
default_country
.
upper
()
)
form_desc
.
add_field
(
"country"
,
label
=
country_label
,
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 terms of service and honor code checkboxes
if
self
.
_is_field_visible
(
"terms_of_service"
):
terms_label
=
_
(
u"Honor Code"
)
terms_link
=
marketing_link
(
"HONOR"
)
terms_text
=
_
(
u"Review the Honor Code"
)
# 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"
)
terms_text
=
_
(
u"Review the Terms of Service and Honor Code"
)
# Translators: "Terms of Service" is a legal document users must agree to
# in order to register a new account.
label
=
_
(
u"I 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
)
# 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
(
"honor_code"
,
label
=
label
,
field_type
=
"checkbox"
,
default
=
False
,
required
=
required
,
error_messages
=
{
"required"
:
error_msg
},
supplementalLink
=
terms_link
,
supplementalText
=
terms_text
)
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"
)
terms_text
=
_
(
u"Review the Terms of Service"
)
# Translators: "Terms of service" is a legal document users must agree to
# in order to register a new account.
label
=
_
(
u"I 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
)
# 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
},
supplementalLink
=
terms_link
,
supplementalText
=
terms_text
)
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
))
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
,
)
class
PasswordResetView
(
APIView
):
"""HTTP end-point for GETting a description of the password reset form. """
...
...
@@ -997,48 +183,7 @@ class PasswordResetView(APIView):
@method_decorator
(
ensure_csrf_cookie
)
def
get
(
self
,
request
):
"""Return a description of the password reset form.
This decouples clients from the API definition:
if the API decides to modify the form, clients won't need
to be updated.
See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description.
Returns:
HttpResponse
"""
form_desc
=
FormDescription
(
"post"
,
reverse
(
"password_change_request"
))
# Translators: This label appears above a field on the password reset
# form meant to hold the user's email address.
email_label
=
_
(
u"Email"
)
# Translators: This example email address is used as a placeholder in
# a field on the password reset form meant to hold the user's email address.
email_placeholder
=
_
(
u"username@domain.com"
)
# Translators: These instructions appear on the password reset form,
# immediately below a field meant to hold the user's email address.
email_instructions
=
_
(
u"The email address you used to register with {platform_name}"
)
.
format
(
platform_name
=
configuration_helpers
.
get_value
(
'PLATFORM_NAME'
,
settings
.
PLATFORM_NAME
)
)
form_desc
.
add_field
(
"email"
,
field_type
=
"email"
,
label
=
email_label
,
placeholder
=
email_placeholder
,
instructions
=
email_instructions
,
restrictions
=
{
"min_length"
:
accounts
.
EMAIL_MIN_LENGTH
,
"max_length"
:
accounts
.
EMAIL_MAX_LENGTH
,
}
)
return
HttpResponse
(
form_desc
.
to_json
(),
content_type
=
"application/json"
)
return
HttpResponse
(
get_password_reset_form
()
.
to_json
(),
content_type
=
"application/json"
)
class
UserViewSet
(
viewsets
.
ReadOnlyModelViewSet
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment