Add Enterprise middleware that injects customer data.
This commit is contained in:
@@ -33,6 +33,7 @@ from openedx.core.djangoapps.embargo.test_utils import restrict_course
|
||||
from openedx.core.djangoapps.user_api.models import UserOrgTag
|
||||
from openedx.core.lib.django_test_client_utils import get_absolute_url
|
||||
from openedx.core.lib.token_utils import JwtBuilder
|
||||
from openedx.features.enterprise_support.tests import FAKE_ENTERPRISE_CUSTOMER
|
||||
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseServiceMockMixin
|
||||
from student.models import CourseEnrollment
|
||||
from student.roles import CourseStaffRole
|
||||
@@ -932,7 +933,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
@httpretty.activate
|
||||
@override_settings(ENTERPRISE_SERVICE_WORKER_USERNAME='enterprise_worker',
|
||||
FEATURES=dict(ENABLE_ENTERPRISE_INTEGRATION=True))
|
||||
def test_enterprise_course_enrollment_with_ec_uuid(self):
|
||||
@patch('openedx.features.enterprise_support.api.enterprise_customer_from_api')
|
||||
def test_enterprise_course_enrollment_with_ec_uuid(self, mock_enterprise_customer_from_api):
|
||||
"""Verify that the enrollment completes when the EnterpriseCourseEnrollment creation succeeds. """
|
||||
UserFactory.create(
|
||||
username='enterprise_worker',
|
||||
@@ -949,6 +951,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
'course_id': unicode(self.course.id),
|
||||
'ec_uuid': 'this-is-a-real-uuid'
|
||||
}
|
||||
mock_enterprise_customer_from_api.return_value = FAKE_ENTERPRISE_CUSTOMER
|
||||
self.mock_enterprise_course_enrollment_post_api()
|
||||
self.mock_consent_missing(**consent_kwargs)
|
||||
self.mock_consent_post(**consent_kwargs)
|
||||
|
||||
@@ -454,8 +454,8 @@ def submit_feedback(request):
|
||||
success = False
|
||||
context = get_feedback_form_context(request)
|
||||
|
||||
#Update the tag info with 'enterprise_learner' if the user belongs to an enterprise customer.
|
||||
enterprise_learner_data = enterprise_api.get_enterprise_learner_data(site=request.site, user=request.user)
|
||||
# Update the tag info with 'enterprise_learner' if the user belongs to an enterprise customer.
|
||||
enterprise_learner_data = enterprise_api.get_enterprise_learner_data(user=request.user)
|
||||
if enterprise_learner_data:
|
||||
context["tags"]["learner_type"] = "enterprise_learner"
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class ContactUsView(View):
|
||||
|
||||
if request.user.is_authenticated():
|
||||
context['user_enrollments'] = CourseEnrollment.enrollments_for_user_with_overviews_preload(request.user)
|
||||
enterprise_learner_data = enterprise_api.get_enterprise_learner_data(site=request.site, user=request.user)
|
||||
enterprise_learner_data = enterprise_api.get_enterprise_learner_data(user=request.user)
|
||||
if enterprise_learner_data:
|
||||
tags.append('enterprise_learner')
|
||||
|
||||
|
||||
@@ -1275,8 +1275,6 @@ MIDDLEWARE_CLASSES = [
|
||||
# Must be after DarkLangMiddleware.
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
|
||||
# 'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
|
||||
'django_comment_client.utils.ViewNameMiddleware',
|
||||
'codejail.django_integration.ConfigureCodeJailMiddleware',
|
||||
|
||||
@@ -1298,6 +1296,9 @@ MIDDLEWARE_CLASSES = [
|
||||
|
||||
'waffle.middleware.WaffleMiddleware',
|
||||
|
||||
# Inserts Enterprise content.
|
||||
'openedx.features.enterprise_support.middleware.EnterpriseMiddleware',
|
||||
|
||||
# This must be last
|
||||
'openedx.core.djangoapps.site_configuration.middleware.SessionCookieDomainOverrideMiddleware',
|
||||
]
|
||||
|
||||
14
lms/urls.py
14
lms/urls.py
@@ -143,7 +143,7 @@ urlpatterns = [
|
||||
|
||||
# TODO: This needs to move to a separate urls.py once the student_account and
|
||||
# student views below find a home together
|
||||
if settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION']:
|
||||
if settings.FEATURES.get('ENABLE_COMBINED_LOGIN_REGISTRATION'):
|
||||
# Backwards compatibility with old URL structure, but serve the new views
|
||||
urlpatterns += [
|
||||
url(r'^login$', student_account_views.login_and_registration_form,
|
||||
@@ -158,12 +158,12 @@ else:
|
||||
url(r'^register$', student_views.register_user, name='register_user'),
|
||||
]
|
||||
|
||||
if settings.FEATURES['ENABLE_MOBILE_REST_API']:
|
||||
if settings.FEATURES.get('ENABLE_MOBILE_REST_API'):
|
||||
urlpatterns += [
|
||||
url(r'^api/mobile/v0.5/', include('mobile_api.urls')),
|
||||
]
|
||||
|
||||
if settings.FEATURES['ENABLE_OPENBADGES']:
|
||||
if settings.FEATURES.get('ENABLE_OPENBADGES'):
|
||||
urlpatterns += [
|
||||
url(r'^api/badges/v1/', include('badges.api.urls', app_name='badges', namespace='badges_api')),
|
||||
]
|
||||
@@ -174,7 +174,7 @@ urlpatterns += [
|
||||
|
||||
|
||||
# sysadmin dashboard, to see what courses are loaded, to delete & load courses
|
||||
if settings.FEATURES['ENABLE_SYSADMIN_DASHBOARD']:
|
||||
if settings.FEATURES.get('ENABLE_SYSADMIN_DASHBOARD'):
|
||||
urlpatterns += [
|
||||
url(r'^sysadmin/', include('dashboard.sysadmin_urls')),
|
||||
]
|
||||
@@ -675,7 +675,7 @@ urlpatterns += [
|
||||
),
|
||||
]
|
||||
|
||||
if settings.FEATURES['ENABLE_TEAMS']:
|
||||
if settings.FEATURES.get('ENABLE_TEAMS'):
|
||||
# Teams endpoints
|
||||
urlpatterns += [
|
||||
url(
|
||||
@@ -831,7 +831,7 @@ if settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD'):
|
||||
external_auth_views.course_specific_register, name='course-specific-register'),
|
||||
]
|
||||
|
||||
if configuration_helpers.get_value('ENABLE_BULK_ENROLLMENT_VIEW', settings.FEATURES['ENABLE_BULK_ENROLLMENT_VIEW']):
|
||||
if configuration_helpers.get_value('ENABLE_BULK_ENROLLMENT_VIEW', settings.FEATURES.get('ENABLE_BULK_ENROLLMENT_VIEW')):
|
||||
urlpatterns += [
|
||||
url(r'^api/bulk_enroll/v1/', include('bulk_enroll.urls')),
|
||||
]
|
||||
@@ -994,7 +994,7 @@ urlpatterns += [
|
||||
]
|
||||
|
||||
# Custom courses on edX (CCX) URLs
|
||||
if settings.FEATURES['CUSTOM_COURSES_EDX']:
|
||||
if settings.FEATURES.get('CUSTOM_COURSES_EDX'):
|
||||
urlpatterns += [
|
||||
url(r'^courses/{}/'.format(settings.COURSE_ID_PATTERN),
|
||||
include('ccx.urls')),
|
||||
|
||||
@@ -161,12 +161,12 @@ class EnterpriseApiClient(object):
|
||||
LOGGER.exception(message)
|
||||
raise EnterpriseApiException(message)
|
||||
|
||||
def fetch_enterprise_learner_data(self, site, user): # pylint: disable=unused-argument
|
||||
def fetch_enterprise_learner_data(self, user):
|
||||
"""
|
||||
Fetch information related to enterprise from the Enterprise Service.
|
||||
|
||||
Example:
|
||||
fetch_enterprise_learner_data(site, user)
|
||||
fetch_enterprise_learner_data(user)
|
||||
|
||||
Argument:
|
||||
site: (Site) site instance
|
||||
@@ -269,17 +269,12 @@ class EnterpriseApiServiceClient(EnterpriseServiceClientMixin, EnterpriseApiClie
|
||||
Fetch enterprise customer with enterprise service user and cache the
|
||||
API response`.
|
||||
"""
|
||||
cache_key = get_cache_key(
|
||||
resource='enterprise-customer',
|
||||
resource_id=uuid,
|
||||
username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME,
|
||||
)
|
||||
enterprise_customer = cache.get(cache_key)
|
||||
enterprise_customer = enterprise_customer_from_cache(uuid=uuid)
|
||||
if not enterprise_customer:
|
||||
endpoint = getattr(self.client, 'enterprise-customer')
|
||||
enterprise_customer = endpoint(uuid).get()
|
||||
if enterprise_customer:
|
||||
cache.set(cache_key, enterprise_customer, settings.ENTERPRISE_API_CACHE_TIMEOUT)
|
||||
cache_enterprise(enterprise_customer)
|
||||
|
||||
return enterprise_customer
|
||||
|
||||
@@ -328,14 +323,79 @@ def enterprise_enabled():
|
||||
return 'enterprise' in settings.INSTALLED_APPS and settings.FEATURES.get('ENABLE_ENTERPRISE_INTEGRATION', False)
|
||||
|
||||
|
||||
def enterprise_is_enabled(otherwise=None):
|
||||
"""Decorator which requires that the Enterprise feature be enabled before the function can run."""
|
||||
def decorator(func):
|
||||
"""Decorator for ensuring the Enterprise feature is enabled."""
|
||||
def wrapper(*args, **kwargs):
|
||||
if enterprise_enabled():
|
||||
return func(*args, **kwargs)
|
||||
return otherwise
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def get_enterprise_customer_cache_key(uuid, username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME):
|
||||
"""The cache key used to get cached Enterprise Customer data."""
|
||||
return get_cache_key(
|
||||
resource='enterprise-customer',
|
||||
resource_id=uuid,
|
||||
username=username,
|
||||
)
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def cache_enterprise(enterprise_customer):
|
||||
"""Cache this customer's data."""
|
||||
cache_key = get_enterprise_customer_cache_key(enterprise_customer['uuid'])
|
||||
cache.set(cache_key, enterprise_customer, settings.ENTERPRISE_API_CACHE_TIMEOUT)
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def enterprise_customer_from_cache(request=None, uuid=None):
|
||||
"""Check all available caches for Enterprise Customer data."""
|
||||
enterprise_customer = None
|
||||
|
||||
# Check if it's cached in the general cache storage.
|
||||
if uuid:
|
||||
cache_key = get_enterprise_customer_cache_key(uuid)
|
||||
enterprise_customer = cache.get(cache_key)
|
||||
|
||||
# Check if it's cached in the session.
|
||||
if not enterprise_customer and request and request.user.is_authenticated():
|
||||
enterprise_customer = request.session.get('enterprise_customer')
|
||||
|
||||
return enterprise_customer
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def enterprise_customer_from_api(request):
|
||||
"""Use an API to get Enterprise Customer data from request context clues."""
|
||||
enterprise_customer = None
|
||||
enterprise_customer_uuid = enterprise_customer_uuid_for_request(request)
|
||||
if enterprise_customer_uuid:
|
||||
# If we were able to obtain an EnterpriseCustomer UUID, go ahead
|
||||
# and use it to attempt to retrieve EnterpriseCustomer details
|
||||
# from the EnterpriseCustomer API.
|
||||
enterprise_api_client = (
|
||||
EnterpriseApiClient(user=request.user)
|
||||
if request.user.is_authenticated()
|
||||
else EnterpriseApiServiceClient()
|
||||
)
|
||||
|
||||
try:
|
||||
enterprise_customer = enterprise_api_client.get_enterprise_customer(enterprise_customer_uuid)
|
||||
except HttpNotFoundError:
|
||||
enterprise_customer = None
|
||||
return enterprise_customer
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def enterprise_customer_uuid_for_request(request):
|
||||
"""
|
||||
Check all the context clues of the request to gather a particular EnterpriseCustomer's UUID.
|
||||
"""
|
||||
if not enterprise_enabled():
|
||||
return None
|
||||
|
||||
enterprise_customer_uuid = None
|
||||
sso_provider_id = request.GET.get('tpa_hint')
|
||||
running_pipeline = get_partial_pipeline(request)
|
||||
if running_pipeline:
|
||||
@@ -355,7 +415,7 @@ def enterprise_customer_uuid_for_request(request):
|
||||
enterprise_customer_identity_provider__provider_id=sso_provider_id
|
||||
).uuid
|
||||
except EnterpriseCustomer.DoesNotExist:
|
||||
pass
|
||||
enterprise_customer_uuid = None
|
||||
else:
|
||||
# Check if we got an Enterprise UUID passed directly as either a query
|
||||
# parameter, or as a value in the Enterprise cookie.
|
||||
@@ -366,50 +426,37 @@ def enterprise_customer_uuid_for_request(request):
|
||||
if not enterprise_customer_uuid and request.user.is_authenticated():
|
||||
# If there's no way to get an Enterprise UUID for the request, check to see
|
||||
# if there's already an Enterprise attached to the requesting user on the backend.
|
||||
learner_data = get_enterprise_learner_data(request.site, request.user)
|
||||
learner_data = get_enterprise_learner_data(request.user)
|
||||
if learner_data:
|
||||
enterprise_customer_uuid = learner_data[0]['enterprise_customer']['uuid']
|
||||
|
||||
return enterprise_customer_uuid
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def enterprise_customer_for_request(request):
|
||||
"""
|
||||
Check all the context clues of the request to determine if
|
||||
the request being made is tied to a particular EnterpriseCustomer.
|
||||
"""
|
||||
enterprise_customer = None
|
||||
enterprise_customer_uuid = enterprise_customer_uuid_for_request(request)
|
||||
if enterprise_customer_uuid:
|
||||
# If we were able to obtain an EnterpriseCustomer UUID, go ahead
|
||||
# and use it to attempt to retrieve EnterpriseCustomer details
|
||||
# from the EnterpriseCustomer API.
|
||||
enterprise_api_client = EnterpriseApiServiceClient()
|
||||
if request.user.is_authenticated():
|
||||
enterprise_api_client = EnterpriseApiClient(user=request.user)
|
||||
|
||||
try:
|
||||
enterprise_customer = enterprise_api_client.get_enterprise_customer(enterprise_customer_uuid)
|
||||
except HttpNotFoundError:
|
||||
enterprise_customer = None
|
||||
|
||||
return enterprise_customer
|
||||
if 'enterprise_customer' in request.session:
|
||||
return enterprise_customer_from_cache(request=request)
|
||||
else:
|
||||
return enterprise_customer_from_api(request)
|
||||
|
||||
|
||||
@enterprise_is_enabled(otherwise=False)
|
||||
def consent_needed_for_course(request, user, course_id, enrollment_exists=False):
|
||||
"""
|
||||
Wrap the enterprise app check to determine if the user needs to grant
|
||||
data sharing permissions before accessing a course.
|
||||
"""
|
||||
if not enterprise_enabled():
|
||||
return False
|
||||
|
||||
consent_key = ('data_sharing_consent_needed', course_id)
|
||||
|
||||
if request.session.get(consent_key) is False:
|
||||
return False
|
||||
|
||||
enterprise_learner_details = get_enterprise_learner_data(request.site, user)
|
||||
enterprise_learner_details = get_enterprise_learner_data(user)
|
||||
if not enterprise_learner_details:
|
||||
consent_needed = False
|
||||
else:
|
||||
@@ -431,15 +478,13 @@ def consent_needed_for_course(request, user, course_id, enrollment_exists=False)
|
||||
return consent_needed
|
||||
|
||||
|
||||
@enterprise_is_enabled(otherwise=set())
|
||||
def get_consent_required_courses(user, course_ids):
|
||||
"""
|
||||
Returns a set of course_ids that require consent
|
||||
Note that this function makes use of the Enterprise models directly instead of using the API calls
|
||||
"""
|
||||
result = set()
|
||||
if not enterprise_enabled():
|
||||
return result
|
||||
|
||||
enterprise_learner = EnterpriseCustomerUser.objects.filter(user_id=user.id).first()
|
||||
if not enterprise_learner or not enterprise_learner.enterprise_customer:
|
||||
return result
|
||||
@@ -456,6 +501,7 @@ def get_consent_required_courses(user, course_ids):
|
||||
return result
|
||||
|
||||
|
||||
@enterprise_is_enabled(otherwise='')
|
||||
def get_enterprise_consent_url(request, course_id, user=None, return_to=None, enrollment_exists=False):
|
||||
"""
|
||||
Build a URL to redirect the user to the Enterprise app to provide data sharing
|
||||
@@ -468,9 +514,6 @@ def get_enterprise_consent_url(request, course_id, user=None, return_to=None, en
|
||||
* return_to: url name label for the page to return to after consent is granted.
|
||||
If None, return to request.path instead.
|
||||
"""
|
||||
if not enterprise_enabled():
|
||||
return ''
|
||||
|
||||
user = user or request.user
|
||||
|
||||
if not consent_needed_for_course(request, user, course_id, enrollment_exists=enrollment_exists):
|
||||
@@ -499,29 +542,24 @@ def get_enterprise_consent_url(request, course_id, user=None, return_to=None, en
|
||||
return full_url
|
||||
|
||||
|
||||
def get_enterprise_learner_data(site, user):
|
||||
@enterprise_is_enabled()
|
||||
def get_enterprise_learner_data(user):
|
||||
"""
|
||||
Client API operation adapter/wrapper
|
||||
"""
|
||||
if not enterprise_enabled():
|
||||
return None
|
||||
|
||||
enterprise_learner_data = EnterpriseApiClient(user=user).fetch_enterprise_learner_data(site=site, user=user)
|
||||
enterprise_learner_data = EnterpriseApiClient(user=user).fetch_enterprise_learner_data(user)
|
||||
if enterprise_learner_data:
|
||||
return enterprise_learner_data['results']
|
||||
|
||||
|
||||
@enterprise_is_enabled(otherwise={})
|
||||
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)
|
||||
enterprise_learner_data = get_enterprise_learner_data(user)
|
||||
if enterprise_learner_data:
|
||||
return enterprise_learner_data[0]['enterprise_customer']
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
@@ -544,6 +582,7 @@ def get_consent_notification_data(enterprise_customer):
|
||||
return title_template, message_template
|
||||
|
||||
|
||||
@enterprise_is_enabled(otherwise='')
|
||||
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.
|
||||
@@ -556,9 +595,6 @@ def get_dashboard_consent_notification(request, user, course_enrollments):
|
||||
Returns:
|
||||
str: Either an empty string, or a string containing the HTML code for the notification banner.
|
||||
"""
|
||||
if not enterprise_enabled():
|
||||
return ''
|
||||
|
||||
enrollment = None
|
||||
consent_needed = False
|
||||
course_id = request.GET.get(CONSENT_FAILED_PARAMETER)
|
||||
@@ -612,14 +648,12 @@ def get_dashboard_consent_notification(request, user, course_enrollments):
|
||||
return ''
|
||||
|
||||
|
||||
@enterprise_is_enabled()
|
||||
def insert_enterprise_pipeline_elements(pipeline):
|
||||
"""
|
||||
If the enterprise app is enabled, insert additional elements into the
|
||||
pipeline related to enterprise.
|
||||
"""
|
||||
if not enterprise_enabled():
|
||||
return
|
||||
|
||||
additional_elements = (
|
||||
'enterprise.tpa_pipeline.handle_enterprise_logistration',
|
||||
)
|
||||
|
||||
29
openedx/features/enterprise_support/middleware.py
Normal file
29
openedx/features/enterprise_support/middleware.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Middleware for the Enterprise feature.
|
||||
|
||||
The Enterprise feature must be turned on for this middleware to have any effect.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import MiddlewareNotUsed
|
||||
|
||||
from openedx.features.enterprise_support import api
|
||||
|
||||
|
||||
class EnterpriseMiddleware(object):
|
||||
"""
|
||||
Middleware that adds Enterprise-related content to the request.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
We don't need to use this middleware if the Enterprise feature isn't enabled.
|
||||
"""
|
||||
if not api.enterprise_enabled():
|
||||
raise MiddlewareNotUsed()
|
||||
|
||||
def process_request(self, request):
|
||||
"""
|
||||
Fill the request with Enterprise-related content.
|
||||
"""
|
||||
if 'enterprise_customer' not in request.session and request.user.is_authenticated():
|
||||
request.session['enterprise_customer'] = api.enterprise_customer_for_request(request)
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
Things commonly needed in Enterprise tests.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
FEATURES_WITH_ENTERPRISE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_ENTERPRISE_ENABLED['ENABLE_ENTERPRISE_INTEGRATION'] = True
|
||||
|
||||
FAKE_ENTERPRISE_CUSTOMER = {
|
||||
'active': True,
|
||||
'branding_configuration': None,
|
||||
'catalog': None,
|
||||
'enable_audit_enrollment': False,
|
||||
'enable_data_sharing_consent': False,
|
||||
'enforce_data_sharing_consent': 'at_enrollment',
|
||||
'enterprise_customer_entitlements': [],
|
||||
'identity_provider': None,
|
||||
'name': 'EnterpriseCustomer',
|
||||
'replace_sensitive_sso_username': True,
|
||||
'site': {'domain': 'example.com', 'name': 'example.com'},
|
||||
'uuid': '1cbf230f-f514-4a05-845e-d57b8e29851c'
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ from django.core.cache import cache
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from openedx.features.enterprise_support.tests import FAKE_ENTERPRISE_CUSTOMER
|
||||
|
||||
|
||||
class EnterpriseServiceMockMixin(object):
|
||||
"""
|
||||
@@ -177,7 +179,8 @@ class EnterpriseServiceMockMixin(object):
|
||||
'enterprise_customer': enterprise_customer_uuid,
|
||||
'entitlement_id': entitlement_id
|
||||
}
|
||||
]
|
||||
],
|
||||
'replace_sensitive_sso_username': True,
|
||||
},
|
||||
'user_id': 5,
|
||||
'user': {
|
||||
@@ -220,6 +223,7 @@ class EnterpriseTestConsentRequired(SimpleTestCase):
|
||||
Mixin to help test the data_sharing_consent_required decorator.
|
||||
"""
|
||||
|
||||
@mock.patch('openedx.features.enterprise_support.api.enterprise_customer_from_api')
|
||||
@mock.patch('openedx.features.enterprise_support.api.enterprise_customer_uuid_for_request')
|
||||
@mock.patch('openedx.features.enterprise_support.api.reverse')
|
||||
@mock.patch('openedx.features.enterprise_support.api.enterprise_enabled')
|
||||
@@ -232,6 +236,7 @@ class EnterpriseTestConsentRequired(SimpleTestCase):
|
||||
mock_enterprise_enabled,
|
||||
mock_reverse,
|
||||
mock_enterprise_customer_uuid_for_request,
|
||||
mock_enterprise_customer_from_api,
|
||||
status_code=200,
|
||||
):
|
||||
"""
|
||||
@@ -247,6 +252,7 @@ class EnterpriseTestConsentRequired(SimpleTestCase):
|
||||
mock_reverse.side_effect = mock_consent_reverse
|
||||
mock_enterprise_enabled.return_value = True
|
||||
mock_enterprise_customer_uuid_for_request.return_value = 'fake-uuid'
|
||||
mock_enterprise_customer_from_api.return_value = FAKE_ENTERPRISE_CUSTOMER
|
||||
# Ensure that when consent is necessary, the user is redirected to the consent page.
|
||||
mock_consent_necessary.return_value = True
|
||||
response = client.get(url)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
Test the enterprise support APIs.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
import ddt
|
||||
import httpretty
|
||||
import mock
|
||||
@@ -15,7 +13,7 @@ from django.http import HttpResponseRedirect
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from consent.models import DataSharingConsent
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms
|
||||
from openedx.features.enterprise_support.api import (
|
||||
ConsentApiClient,
|
||||
ConsentApiServiceClient,
|
||||
@@ -30,16 +28,13 @@ from openedx.features.enterprise_support.api import (
|
||||
insert_enterprise_pipeline_elements,
|
||||
enterprise_enabled,
|
||||
)
|
||||
from openedx.features.enterprise_support.tests import FEATURES_WITH_ENTERPRISE_ENABLED
|
||||
from openedx.features.enterprise_support.tests.factories import EnterpriseCustomerUserFactory
|
||||
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseServiceMockMixin
|
||||
from openedx.features.enterprise_support.utils import get_cache_key
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
|
||||
FEATURES_WITH_ENTERPRISE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_ENTERPRISE_ENABLED['ENABLE_ENTERPRISE_INTEGRATION'] = True
|
||||
|
||||
|
||||
class MockEnrollment(mock.MagicMock):
|
||||
"""
|
||||
Mock object for an enrollment which has a consistent string representation
|
||||
@@ -51,7 +46,7 @@ class MockEnrollment(mock.MagicMock):
|
||||
|
||||
@ddt.ddt
|
||||
@override_settings(FEATURES=FEATURES_WITH_ENTERPRISE_ENABLED)
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@skip_unless_lms
|
||||
class TestEnterpriseApi(EnterpriseServiceMockMixin, CacheIsolationTestCase):
|
||||
"""
|
||||
Test enterprise support APIs.
|
||||
|
||||
66
openedx/features/enterprise_support/tests/test_middleware.py
Normal file
66
openedx/features/enterprise_support/tests/test_middleware.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
Tests for Enterprise middleware.
|
||||
"""
|
||||
|
||||
import mock
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
from openedx.features.enterprise_support.tests import (
|
||||
FAKE_ENTERPRISE_CUSTOMER, FEATURES_WITH_ENTERPRISE_ENABLED,
|
||||
factories
|
||||
)
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WITH_ENTERPRISE_ENABLED)
|
||||
@skip_unless_lms
|
||||
class EnterpriseMiddlewareTest(TestCase):
|
||||
"""
|
||||
Test for `EnterpriseMiddleware`.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Initiate commonly needed objects."""
|
||||
super(EnterpriseMiddlewareTest, self).setUp()
|
||||
|
||||
# Customer & Learner details.
|
||||
self.user = UserFactory.create(username='username', password='password')
|
||||
self.enterprise_customer = FAKE_ENTERPRISE_CUSTOMER
|
||||
self.enterprise_learner = factories.EnterpriseCustomerUserFactory(user_id=self.user.id)
|
||||
|
||||
# Request details.
|
||||
self.client.login(username='username', password='password')
|
||||
self.dashboard = reverse('dashboard')
|
||||
|
||||
# Mocks.
|
||||
patcher = mock.patch('openedx.features.enterprise_support.api.enterprise_customer_from_api')
|
||||
self.mock_enterprise_customer_from_api = patcher.start()
|
||||
self.mock_enterprise_customer_from_api.return_value = self.enterprise_customer
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
def test_anonymous_user(self):
|
||||
"""The `enterprise_customer` is not set in the session if the user is anonymous."""
|
||||
self.client.logout()
|
||||
self.client.get(self.dashboard)
|
||||
assert self.client.session.get('enterprise_customer') is None
|
||||
|
||||
def test_enterprise_customer(self):
|
||||
"""The `enterprise_customer` gets set in the session."""
|
||||
self.client.get(self.dashboard)
|
||||
assert self.client.session.get('enterprise_customer') == self.enterprise_customer
|
||||
|
||||
def test_enterprise_customer_cached(self):
|
||||
"""The middleware doesn't attempt to refill `enterprise_customer` if it already exists in the session."""
|
||||
assert not self.mock_enterprise_customer_from_api.called
|
||||
|
||||
# First call populates the session by calling the API.
|
||||
self.client.get(self.dashboard)
|
||||
assert self.mock_enterprise_customer_from_api.call_count == 1
|
||||
|
||||
# Second same call has no need to call the API because the session already contains the data.
|
||||
self.client.get(self.dashboard)
|
||||
assert self.mock_enterprise_customer_from_api.call_count == 1
|
||||
@@ -115,13 +115,13 @@ edx-django-oauth2-provider==1.2.5
|
||||
edx-django-release-util==0.3.1
|
||||
edx-django-sites-extensions==2.3.1
|
||||
edx-drf-extensions==1.2.5
|
||||
edx-enterprise==0.67.5
|
||||
edx-enterprise==0.67.6
|
||||
edx-i18n-tools==0.4.4
|
||||
edx-milestones==0.1.13
|
||||
edx-oauth2-provider==1.2.2
|
||||
edx-opaque-keys[django]==0.4.4
|
||||
edx-organizations==0.4.10
|
||||
edx-proctoring==1.3.9
|
||||
edx-proctoring==1.4.0
|
||||
edx-rest-api-client==1.7.1
|
||||
edx-search==1.1.0
|
||||
edx-submissions==2.0.12
|
||||
|
||||
@@ -134,14 +134,14 @@ edx-django-oauth2-provider==1.2.5
|
||||
edx-django-release-util==0.3.1
|
||||
edx-django-sites-extensions==2.3.1
|
||||
edx-drf-extensions==1.2.5
|
||||
edx-enterprise==0.67.5
|
||||
edx-enterprise==0.67.6
|
||||
edx-i18n-tools==0.4.4
|
||||
edx-lint==0.5.4
|
||||
edx-milestones==0.1.13
|
||||
edx-oauth2-provider==1.2.2
|
||||
edx-opaque-keys[django]==0.4.4
|
||||
edx-organizations==0.4.10
|
||||
edx-proctoring==1.3.9
|
||||
edx-proctoring==1.4.0
|
||||
edx-rest-api-client==1.7.1
|
||||
edx-search==1.1.0
|
||||
edx-sphinx-theme==1.3.0
|
||||
@@ -328,4 +328,4 @@ xblock-review==1.1.5
|
||||
xblock==1.1.1
|
||||
xmltodict==0.4.1
|
||||
zendesk==1.1.1
|
||||
zope.interface==4.4.3
|
||||
zope.interface==4.5.0
|
||||
|
||||
@@ -129,14 +129,14 @@ edx-django-oauth2-provider==1.2.5
|
||||
edx-django-release-util==0.3.1
|
||||
edx-django-sites-extensions==2.3.1
|
||||
edx-drf-extensions==1.2.5
|
||||
edx-enterprise==0.67.5
|
||||
edx-enterprise==0.67.6
|
||||
edx-i18n-tools==0.4.4
|
||||
edx-lint==0.5.4
|
||||
edx-milestones==0.1.13
|
||||
edx-oauth2-provider==1.2.2
|
||||
edx-opaque-keys[django]==0.4.4
|
||||
edx-organizations==0.4.10
|
||||
edx-proctoring==1.3.9
|
||||
edx-proctoring==1.4.0
|
||||
edx-rest-api-client==1.7.1
|
||||
edx-search==1.1.0
|
||||
edx-submissions==2.0.12
|
||||
@@ -311,4 +311,4 @@ xblock-review==1.1.5
|
||||
xblock==1.1.1
|
||||
xmltodict==0.4.1
|
||||
zendesk==1.1.1
|
||||
zope.interface==4.4.3 # via twisted
|
||||
zope.interface==4.5.0 # via twisted
|
||||
|
||||
Reference in New Issue
Block a user