From 8961ec4f359abd0ef87649f8790e0f53f68b0f5c Mon Sep 17 00:00:00 2001 From: Renzo Lucioni Date: Wed, 26 Nov 2014 14:18:47 -0500 Subject: [PATCH] Update the student views to accept the email_opt_in parameter Includes tests checking that the student views integrate with the profile API as expected. --- .../student/tests/test_enrollment.py | 36 ++++++++++++++++++- common/djangoapps/student/views.py | 11 ++++++ common/djangoapps/util/cache.py | 10 ++---- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/common/djangoapps/student/tests/test_enrollment.py b/common/djangoapps/student/tests/test_enrollment.py index 920803d34c..b616f40f1c 100644 --- a/common/djangoapps/student/tests/test_enrollment.py +++ b/common/djangoapps/student/tests/test_enrollment.py @@ -3,6 +3,7 @@ Tests for student enrollment. """ import ddt import unittest +from mock import patch from django.test.utils import override_settings from django.conf import settings @@ -104,6 +105,33 @@ class EnrollmentTest(ModuleStoreTestCase): # Expect that we're no longer enrolled self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id)) + @patch.dict(settings.FEATURES, {'ENABLE_MKTG_EMAIL_OPT_IN': True}) + @patch('user_api.api.profile.update_email_opt_in') + @ddt.data( + ([], 'true'), + ([], 'false'), + (['honor', 'verified'], 'true'), + (['honor', 'verified'], 'false'), + (['professional'], 'true'), + (['professional'], 'false'), + ) + @ddt.unpack + def test_enroll_with_email_opt_in(self, course_modes, email_opt_in, mock_update_email_opt_in): + # Create the course modes (if any) required for this test case + for mode_slug in course_modes: + CourseModeFactory.create( + course_id=self.course.id, + mode_slug=mode_slug, + mode_display_name=mode_slug, + ) + + # Enroll in the course + self._change_enrollment('enroll', email_opt_in=email_opt_in) + + # Verify that the profile API has been called as expected + opt_in = email_opt_in == 'true' + mock_update_email_opt_in.assert_called_once_with(self.USERNAME, self.course.org, opt_in) + def test_user_not_authenticated(self): # Log out, so we're no longer authenticated self.client.logout() @@ -133,7 +161,7 @@ class EnrollmentTest(ModuleStoreTestCase): resp = self._change_enrollment('unenroll', course_id="edx/") self.assertEqual(resp.status_code, 400) - def _change_enrollment(self, action, course_id=None): + def _change_enrollment(self, action, course_id=None, email_opt_in=None): """Change the student's enrollment status in a course. Args: @@ -142,6 +170,8 @@ class EnrollmentTest(ModuleStoreTestCase): Keyword Args: course_id (unicode): If provided, use this course ID. Otherwise, use the course ID created in the setup for this test. + email_opt_in (unicode): If provided, pass this value along as + an additional GET parameter. Returns: Response @@ -154,4 +184,8 @@ class EnrollmentTest(ModuleStoreTestCase): 'enrollment_action': action, 'course_id': course_id } + + if email_opt_in: + params['email_opt_in'] = email_opt_in + return self.client.post(reverse('change_enrollment'), params) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 9429502cae..c176e755f4 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -102,6 +102,7 @@ from third_party_auth import pipeline, provider from student.helpers import auth_pipeline_urls, set_logged_in_cookie from xmodule.error_module import ErrorDescriptor from shoppingcart.models import CourseRegistrationCode +from user_api.api import profile as profile_api import analytics from eventtracking import tracker @@ -739,6 +740,12 @@ def try_change_enrollment(request): log.exception("Exception automatically enrolling after login: %s", exc) +def _update_email_opt_in(request, username, org): + """Helper function used to hit the profile API if email opt-in is enabled.""" + email_opt_in = request.POST.get('email_opt_in') == 'true' + profile_api.update_email_opt_in(username, org, email_opt_in) + + @require_POST @commit_on_success_with_read_committed def change_enrollment(request, check_access=True): @@ -804,6 +811,10 @@ def change_enrollment(request, check_access=True): .format(user.username, course_id)) return HttpResponseBadRequest(_("Course id is invalid")) + # Record the user's email opt-in preference + if settings.FEATURES.get('ENABLE_MKTG_EMAIL_OPT_IN'): + _update_email_opt_in(request, user.username, course_id.org) + available_modes = CourseMode.modes_for_course_dict(course_id) # Check that auto enrollment is allowed for this course diff --git a/common/djangoapps/util/cache.py b/common/djangoapps/util/cache.py index cede8acb71..50b1b469ba 100644 --- a/common/djangoapps/util/cache.py +++ b/common/djangoapps/util/cache.py @@ -43,17 +43,13 @@ def cache_if_anonymous(*get_parameters): @cache_if_anonymous() def myView(request): """ - def decorator(view_func): - """The outer wrapper, used to allow the decorator to take optional - arguments. - """ + """The outer wrapper, used to allow the decorator to take optional arguments.""" @wraps(view_func) def wrapper(request, *args, **kwargs): """The inner wrapper, which wraps the view function.""" if not request.user.is_authenticated(): - #Use the cache - # same view accessed through different domain names may + # Use the cache. The same view accessed through different domain names may # return different things, so include the domain name in the key. domain = str(request.META.get('HTTP_HOST')) + '.' cache_key = domain + "cache_if_anonymous." + get_language() + '.' + request.path @@ -70,7 +66,7 @@ def cache_if_anonymous(*get_parameters): return response else: - #Don't use the cache + # Don't use the cache. return view_func(request, *args, **kwargs) return wrapper