diff --git a/lms/djangoapps/student_account/test/test_views.py b/lms/djangoapps/student_account/test/test_views.py
index 8bca85b5ca..f796ec4750 100644
--- a/lms/djangoapps/student_account/test/test_views.py
+++ b/lms/djangoapps/student_account/test/test_views.py
@@ -866,10 +866,10 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
MessageMiddleware().process_request(self.request)
messages.error(self.request, 'Facebook is already in use.', extra_tags='Auth facebook')
- @mock.patch('student_account.views.get_enterprise_learner_data')
- def test_context(self, mock_get_enterprise_learner_data):
+ @mock.patch('openedx.features.enterprise_support.api.get_enterprise_customer_for_learner')
+ def test_context(self, mock_get_enterprise_customer_for_learner):
self.request.site = SiteFactory.create()
- mock_get_enterprise_learner_data.return_value = []
+ mock_get_enterprise_customer_for_learner.return_value = {}
context = account_settings_context(self.request)
user_accounts_api_url = reverse("accounts_api", kwargs={'username': self.user.username})
@@ -899,19 +899,17 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
context['enterprise_readonly_account_fields'], {'fields': settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS}
)
- @mock.patch('student_account.views.get_enterprise_learner_data')
- @mock.patch('student_account.views.third_party_auth.provider.Registry.get')
+ @mock.patch('student_account.views.get_enterprise_customer_for_learner')
+ @mock.patch('openedx.features.enterprise_support.utils.third_party_auth.provider.Registry.get')
def test_context_for_enterprise_learner(
- self, mock_get_auth_provider, mock_get_enterprise_learner_data
+ self, mock_get_auth_provider, mock_get_enterprise_customer_for_learner
):
dummy_enterprise_customer = {
'uuid': 'real-ent-uuid',
'name': 'Dummy Enterprise',
'identity_provider': 'saml-ubc'
}
- mock_get_enterprise_learner_data.return_value = [
- {'enterprise_customer': dummy_enterprise_customer}
- ]
+ mock_get_enterprise_customer_for_learner.return_value = dummy_enterprise_customer
self.request.site = SiteFactory.create()
mock_get_auth_provider.return_value.sync_learner_profile_data = True
context = account_settings_context(self.request)
diff --git a/lms/djangoapps/student_account/views.py b/lms/djangoapps/student_account/views.py
index 3a6fcc62b7..c3200e6522 100644
--- a/lms/djangoapps/student_account/views.py
+++ b/lms/djangoapps/student_account/views.py
@@ -39,9 +39,13 @@ from openedx.core.djangoapps.user_api.errors import (
)
from openedx.core.lib.edx_api_utils import get_edx_api_data
from openedx.core.lib.time_zone_utils import TIME_ZONE_CHOICES
-from openedx.features.enterprise_support.api import enterprise_customer_for_request, get_enterprise_learner_data
+from openedx.features.enterprise_support.api import enterprise_customer_for_request, get_enterprise_customer_for_learner
from student.cookies import set_experiments_is_enterprise_cookie
-from openedx.features.enterprise_support.utils import update_third_party_auth_context_for_enterprise
+from openedx.features.enterprise_support.utils import (
+ handle_enterprise_cookies_for_logistration,
+ update_logistration_context_for_enterprise,
+ update_account_settings_context_for_enterprise,
+)
from student.helpers import destroy_oauth_tokens, get_next_url_for_login_page
from student.models import UserProfile
from student.views import register_user as old_register_view
@@ -160,20 +164,11 @@ def login_and_registration_form(request, initial_mode="login"):
),
}
- context = update_context_for_enterprise(request, context)
+ enterprise_customer = enterprise_customer_for_request(request)
+ update_logistration_context_for_enterprise(request, context, enterprise_customer)
response = render_to_response('student_account/login_and_register.html', context)
-
- # This cookie can be used for tests or minor features,
- # but should not be used for payment related or other critical work
- # since users can edit their cookies
- set_experiments_is_enterprise_cookie(request, response, context['enable_enterprise_sidebar'])
-
- # Remove enterprise cookie so that subsequent requests show default login page.
- response.delete_cookie(
- configuration_helpers.get_value("ENTERPRISE_CUSTOMER_COOKIE_NAME", settings.ENTERPRISE_CUSTOMER_COOKIE_NAME),
- domain=configuration_helpers.get_value("BASE_COOKIE_DOMAIN", settings.BASE_COOKIE_DOMAIN),
- )
+ handle_enterprise_cookies_for_logistration(request, response, context)
return response
@@ -232,85 +227,6 @@ def password_change_request_handler(request):
return HttpResponseBadRequest(_("No email address provided."))
-def update_context_for_enterprise(request, context):
- """
- Take the processed context produced by the view, determine if it's relevant
- to a particular Enterprise Customer, and update it to include that customer's
- enterprise metadata.
- """
-
- context = context.copy()
-
- sidebar_context = enterprise_sidebar_context(request)
-
- if sidebar_context:
- context['data']['registration_form_desc']['fields'] = enterprise_fields_only(
- context['data']['registration_form_desc']
- )
- context.update(sidebar_context)
- context['enable_enterprise_sidebar'] = True
- context['data']['hide_auth_warnings'] = True
- else:
- context['enable_enterprise_sidebar'] = False
-
- return context
-
-
-def enterprise_fields_only(fields):
- """
- Take the received field definition, and exclude those fields that we don't want
- to require if the user is going to be a member of an Enterprise Customer.
- """
- enterprise_exclusions = configuration_helpers.get_value(
- 'ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS',
- settings.ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS
- )
- return [field for field in fields['fields'] if field['name'] not in enterprise_exclusions]
-
-
-def enterprise_sidebar_context(request):
- """
- Given the current request, render the HTML of a sidebar for the current
- logistration view that depicts Enterprise-related information.
- """
- enterprise_customer = enterprise_customer_for_request(request)
-
- if not enterprise_customer:
- return {}
-
- platform_name = configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
-
- branding_configuration = enterprise_customer.get('branding_configuration', {})
- logo_url = branding_configuration.get('logo', '') if isinstance(branding_configuration, dict) else ''
-
- branded_welcome_template = configuration_helpers.get_value(
- 'ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE',
- settings.ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE
- )
-
- branded_welcome_string = branded_welcome_template.format(
- start_bold=u'',
- end_bold=u'',
- enterprise_name=enterprise_customer['name'],
- platform_name=platform_name
- )
-
- platform_welcome_template = configuration_helpers.get_value(
- 'ENTERPRISE_PLATFORM_WELCOME_TEMPLATE',
- settings.ENTERPRISE_PLATFORM_WELCOME_TEMPLATE
- )
- platform_welcome_string = platform_welcome_template.format(platform_name=platform_name)
-
- context = {
- 'enterprise_name': enterprise_customer['name'],
- 'enterprise_logo_url': logo_url,
- 'enterprise_branded_welcome_string': branded_welcome_string,
- 'platform_welcome_string': platform_welcome_string,
- }
-
- return context
-
-
def _third_party_auth_context(request, redirect_to, tpa_hint=None):
"""Context for third party auth providers and the currently running pipeline.
@@ -337,26 +253,24 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
}
if third_party_auth.is_enabled():
- enterprise_customer = enterprise_customer_for_request(request)
- if not enterprise_customer:
- for enabled in third_party_auth.provider.Registry.displayed_for_login(tpa_hint=tpa_hint):
- info = {
- "id": enabled.provider_id,
- "name": enabled.name,
- "iconClass": enabled.icon_class or None,
- "iconImage": enabled.icon_image.url if enabled.icon_image else None,
- "loginUrl": pipeline.get_login_url(
- enabled.provider_id,
- pipeline.AUTH_ENTRY_LOGIN,
- redirect_url=redirect_to,
- ),
- "registerUrl": pipeline.get_login_url(
- enabled.provider_id,
- pipeline.AUTH_ENTRY_REGISTER,
- redirect_url=redirect_to,
- ),
- }
- context["providers" if not enabled.secondary else "secondaryProviders"].append(info)
+ for enabled in third_party_auth.provider.Registry.displayed_for_login(tpa_hint=tpa_hint):
+ info = {
+ "id": enabled.provider_id,
+ "name": enabled.name,
+ "iconClass": enabled.icon_class or None,
+ "iconImage": enabled.icon_image.url if enabled.icon_image else None,
+ "loginUrl": pipeline.get_login_url(
+ enabled.provider_id,
+ pipeline.AUTH_ENTRY_LOGIN,
+ redirect_url=redirect_to,
+ ),
+ "registerUrl": pipeline.get_login_url(
+ enabled.provider_id,
+ pipeline.AUTH_ENTRY_REGISTER,
+ redirect_url=redirect_to,
+ ),
+ }
+ context["providers" if not enabled.secondary else "secondaryProviders"].append(info)
running_pipeline = pipeline.get(request)
if running_pipeline is not None:
@@ -368,19 +282,8 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
context["syncLearnerProfileData"] = current_provider.sync_learner_profile_data
if current_provider.skip_registration_form:
- # For enterprise (and later for everyone), we need to get explicit consent to the
- # Terms of service instead of auto submitting the registration form outright.
- if not enterprise_customer:
- # As a reliable way of "skipping" the registration form, we just submit it automatically
- context["autoSubmitRegForm"] = True
- else:
- context["autoRegisterWelcomeMessage"] = (
- 'Thank you for joining {}. '
- 'Just a couple steps before you start learning!'
- ).format(
- configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
- )
- context["registerFormSubmitButtonText"] = _("Continue")
+ # As a reliable way of "skipping" the registration form, we just submit it automatically
+ context["autoSubmitRegForm"] = True
# Check for any error messages we may want to display:
for msg in messages.get_messages(request):
@@ -389,8 +292,6 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
context['errorMessage'] = _(unicode(msg)) # pylint: disable=translation-of-non-string
break
- context = update_third_party_auth_context_for_enterprise(context, enterprise_customer)
-
return context
@@ -638,21 +539,8 @@ def account_settings_context(request):
'extended_profile_fields': _get_extended_profile_fields(),
}
- enterprise_customer_name = None
- sync_learner_profile_data = False
- enterprise_learner_data = get_enterprise_learner_data(site=request.site, user=request.user)
- if enterprise_learner_data:
- enterprise_customer_name = enterprise_learner_data[0]['enterprise_customer']['name']
- enterprise_idp = enterprise_learner_data[0]['enterprise_customer']['identity_provider']
- identity_provider = third_party_auth.provider.Registry.get(provider_id=enterprise_idp)
- sync_learner_profile_data = identity_provider.sync_learner_profile_data if identity_provider else False
-
- context['sync_learner_profile_data'] = sync_learner_profile_data
- context['edx_support_url'] = configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK)
- context['enterprise_name'] = enterprise_customer_name
- context['enterprise_readonly_account_fields'] = {
- 'fields': settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS
- }
+ enterprise_customer = get_enterprise_customer_for_learner(site=request.site, user=request.user)
+ update_account_settings_context_for_enterprise(context, enterprise_customer)
if third_party_auth.is_enabled():
# If the account on the third party provider is already connected with another edX account,
diff --git a/openedx/features/enterprise_support/api.py b/openedx/features/enterprise_support/api.py
index a35350a846..ed614f7ca9 100644
--- a/openedx/features/enterprise_support/api.py
+++ b/openedx/features/enterprise_support/api.py
@@ -485,6 +485,20 @@ def get_enterprise_learner_data(site, user):
return enterprise_learner_data['results']
+def get_enterprise_customer_for_learner(site, user):
+ """
+ Return enterprise customer to whom given learner belongs.
+ """
+ if not enterprise_enabled():
+ return {}
+
+ enterprise_learner_data = get_enterprise_learner_data(site, user)
+ if enterprise_learner_data:
+ return enterprise_learner_data[0]['enterprise_customer']
+
+ return {}
+
+
def get_dashboard_consent_notification(request, user, course_enrollments):
"""
If relevant to the request at hand, create a banner on the dashboard indicating consent failed.
diff --git a/openedx/features/enterprise_support/utils.py b/openedx/features/enterprise_support/utils.py
index 8878f2da04..3620749637 100644
--- a/openedx/features/enterprise_support/utils.py
+++ b/openedx/features/enterprise_support/utils.py
@@ -5,6 +5,11 @@ import hashlib
import six
from django.conf import settings
from django.utils.translation import ugettext as _
+
+import third_party_auth
+from third_party_auth import pipeline
+from student.cookies import set_experiments_is_enterprise_cookie
+
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangolib.markup import HTML, Text
@@ -33,11 +38,96 @@ def get_cache_key(**kwargs):
return hashlib.md5(key).hexdigest()
-def update_third_party_auth_context_for_enterprise(context, enterprise_customer=None):
+def update_logistration_context_for_enterprise(request, context, enterprise_customer):
+ """
+ Take the processed context produced by the view, determine if it's relevant
+ to a particular Enterprise Customer, and update it to include that customer's
+ enterprise metadata.
+
+ Arguments:
+ request (HttpRequest): The request for the logistration page.
+ context (dict): Context for logistration page.
+ enterprise_customer (dict): data for enterprise customer
+
+ """
+ sidebar_context = {}
+ if enterprise_customer:
+ sidebar_context = get_enterprise_sidebar_context(enterprise_customer)
+
+ if sidebar_context:
+ context['data']['registration_form_desc']['fields'] = enterprise_fields_only(
+ context['data']['registration_form_desc']
+ )
+ context.update(sidebar_context)
+ context['enable_enterprise_sidebar'] = True
+ context['data']['hide_auth_warnings'] = True
+ else:
+ context['enable_enterprise_sidebar'] = False
+
+ update_third_party_auth_context_for_enterprise(request, context, enterprise_customer)
+
+
+def get_enterprise_sidebar_context(enterprise_customer):
+ """
+ Get context information for enterprise sidebar for the given enterprise customer.
+
+ Enterprise Sidebar Context has the following key-value pairs.
+ {
+ 'enterprise_name': 'Enterprise Name',
+ 'enterprise_logo_url': 'URL of the enterprise logo image',
+ 'enterprise_branded_welcome_string': 'Human readable welcome message customized for the enterprise',
+ 'platform_welcome_string': 'Human readable welcome message for an enterprise learner',
+ }
+ """
+ platform_name = configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
+
+ branding_configuration = enterprise_customer.get('branding_configuration', {})
+ logo_url = branding_configuration.get('logo', '') if isinstance(branding_configuration, dict) else ''
+
+ branded_welcome_template = configuration_helpers.get_value(
+ 'ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE',
+ settings.ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE
+ )
+
+ branded_welcome_string = branded_welcome_template.format(
+ start_bold=u'',
+ end_bold=u'',
+ enterprise_name=enterprise_customer['name'],
+ platform_name=platform_name
+ )
+
+ platform_welcome_template = configuration_helpers.get_value(
+ 'ENTERPRISE_PLATFORM_WELCOME_TEMPLATE',
+ settings.ENTERPRISE_PLATFORM_WELCOME_TEMPLATE
+ )
+ platform_welcome_string = platform_welcome_template.format(platform_name=platform_name)
+
+ return {
+ 'enterprise_name': enterprise_customer['name'],
+ 'enterprise_logo_url': logo_url,
+ 'enterprise_branded_welcome_string': branded_welcome_string,
+ 'platform_welcome_string': platform_welcome_string,
+ }
+
+
+def enterprise_fields_only(fields):
+ """
+ Take the received field definition, and exclude those fields that we don't want
+ to require if the user is going to be a member of an Enterprise Customer.
+ """
+ enterprise_exclusions = configuration_helpers.get_value(
+ 'ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS',
+ settings.ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS
+ )
+ return [field for field in fields['fields'] if field['name'] not in enterprise_exclusions]
+
+
+def update_third_party_auth_context_for_enterprise(request, context, enterprise_customer=None):
"""
Return updated context of third party auth with modified for enterprise.
Arguments:
+ request (HttpRequest): The request for the logistration page.
context (dict): Context for third party auth providers and auth pipeline.
enterprise_customer (dict): data for enterprise customer
@@ -45,8 +135,8 @@ def update_third_party_auth_context_for_enterprise(context, enterprise_customer=
context (dict): Updated context of third party auth with modified
`errorMessage`.
"""
- if enterprise_customer and context['errorMessage']:
- context['errorMessage'] = Text(_(
+ if enterprise_customer and context['data']['third_party_auth']['errorMessage']:
+ context['data']['third_party_auth']['errorMessage'] = Text(_(
u'We are sorry, you are not authorized to access {platform_name} via this channel. '
u'Please contact your {enterprise} administrator in order to access {platform_name} '
u'or contact {edx_support_link}.{line_break}'
@@ -55,7 +145,7 @@ def update_third_party_auth_context_for_enterprise(context, enterprise_customer=
).format(
platform_name=configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
enterprise=enterprise_customer['name'],
- error_message=context['errorMessage'],
+ error_message=context['data']['third_party_auth']['errorMessage'],
edx_support_link=HTML(
'{support_url_name}'
).format(
@@ -67,4 +157,74 @@ def update_third_party_auth_context_for_enterprise(context, enterprise_customer=
line_break=HTML('
')
)
+ if enterprise_customer:
+ context['data']['third_party_auth']['providers'] = []
+ context['data']['third_party_auth']['secondaryProviders'] = []
+
+ running_pipeline = pipeline.get(request)
+ if running_pipeline is not None:
+ current_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline)
+ if current_provider is not None and current_provider.skip_registration_form and enterprise_customer:
+ # For enterprise (and later for everyone), we need to get explicit consent to the
+ # Terms of service instead of auto submitting the registration form outright.
+ context['data']['third_party_auth']['autoSubmitRegForm'] = False
+ context['data']['third_party_auth']['autoRegisterWelcomeMessage'] = Text(_(
+ 'Thank you for joining {platform_name}. '
+ 'Just a couple steps before you start learning!')
+ ).format(
+ platform_name=configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
+ )
+ context['data']['third_party_auth']['registerFormSubmitButtonText'] = _('Continue')
+
return context
+
+
+def handle_enterprise_cookies_for_logistration(request, response, context):
+ """
+ Helper method for setting or deleting enterprise cookies on logistration response.
+
+ Arguments:
+ request (HttpRequest): The request for the logistration page.
+ response (HttpResponse): The response for the logistration page.
+ context (dict): Context for logistration page.
+
+ """
+ # This cookie can be used for tests or minor features,
+ # but should not be used for payment related or other critical work
+ # since users can edit their cookies
+ set_experiments_is_enterprise_cookie(request, response, context['enable_enterprise_sidebar'])
+
+ # Remove enterprise cookie so that subsequent requests show default login page.
+ response.delete_cookie(
+ configuration_helpers.get_value('ENTERPRISE_CUSTOMER_COOKIE_NAME', settings.ENTERPRISE_CUSTOMER_COOKIE_NAME),
+ domain=configuration_helpers.get_value('BASE_COOKIE_DOMAIN', settings.BASE_COOKIE_DOMAIN),
+ )
+
+
+def update_account_settings_context_for_enterprise(context, enterprise_customer):
+ """
+ Take processed context for account settings page and update it taking enterprise customer into account.
+
+ Arguments:
+ context (dict): Context for account settings page.
+ enterprise_customer (dict): data for enterprise customer
+
+ """
+ enterprise_context = {
+ 'enterprise_name': None,
+ 'sync_learner_profile_data': False,
+ 'edx_support_url': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK),
+ 'enterprise_readonly_account_fields': {
+ 'fields': settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS
+ }
+ }
+
+ if enterprise_customer:
+ enterprise_context['enterprise_name'] = enterprise_customer['name']
+ identity_provider = third_party_auth.provider.Registry.get(
+ provider_id=enterprise_customer['identity_provider'],
+ )
+ if identity_provider:
+ enterprise_context['sync_learner_profile_data'] = identity_provider.sync_learner_profile_data
+
+ context.update(enterprise_context)