Support setting email opt-in in calls to the Otto shim
XCOM-499
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
""" Commerce API v0 view tests. """
|
||||
import json
|
||||
import itertools
|
||||
from uuid import uuid4
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
import ddt
|
||||
from django.conf import settings
|
||||
@@ -9,6 +9,7 @@ from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
import mock
|
||||
from nose.plugins.attrib import attr
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
@@ -33,7 +34,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
"""
|
||||
Tests for the commerce orders view.
|
||||
"""
|
||||
def _post_to_view(self, course_id=None):
|
||||
def _post_to_view(self, course_id=None, marketing_email_opt_in=False):
|
||||
"""
|
||||
POST to the view being tested.
|
||||
|
||||
@@ -42,8 +43,12 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
|
||||
:return: Response
|
||||
"""
|
||||
course_id = unicode(course_id or self.course.id)
|
||||
return self.client.post(self.url, {'course_id': course_id})
|
||||
payload = {
|
||||
"course_id": unicode(course_id or self.course.id)
|
||||
}
|
||||
if marketing_email_opt_in:
|
||||
payload["email_opt_in"] = True
|
||||
return self.client.post(self.url, payload)
|
||||
|
||||
def assertResponseMessage(self, response, expected_msg):
|
||||
""" Asserts the detail field in the response's JSON body equals the expected message. """
|
||||
@@ -297,6 +302,28 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
with mock_create_basket():
|
||||
self._test_successful_ecommerce_api_call(False)
|
||||
|
||||
@mock.patch('commerce.api.v0.views.update_email_opt_in')
|
||||
@ddt.data(*itertools.product((False, True), (False, True), (False, True)))
|
||||
@ddt.unpack
|
||||
def test_marketing_email_opt_in(self, is_opt_in, has_sku, is_exception, mock_update):
|
||||
"""
|
||||
Ensures the email opt-in flag is handled, if present, and that problems handling the
|
||||
flag don't cause the rest of the enrollment transaction to fail.
|
||||
"""
|
||||
if not has_sku:
|
||||
for course_mode in CourseMode.objects.filter(course_id=self.course.id):
|
||||
course_mode.sku = None
|
||||
course_mode.save()
|
||||
|
||||
if is_exception:
|
||||
mock_update.side_effect = Exception("boink")
|
||||
|
||||
return_value = {'id': TEST_BASKET_ID, 'payment_data': None, 'order': {'number': TEST_ORDER_NUMBER}}
|
||||
with mock_create_basket(response=return_value, expect_called=has_sku):
|
||||
response = self._post_to_view(marketing_email_opt_in=is_opt_in)
|
||||
self.assertEqual(mock_update.called, is_opt_in)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
@attr('shard_1')
|
||||
@override_settings(ECOMMERCE_API_URL=TEST_API_URL, ECOMMERCE_API_SIGNING_KEY=TEST_API_SIGNING_KEY)
|
||||
|
||||
@@ -19,6 +19,7 @@ from courseware import courses
|
||||
from embargo import api as embargo_api
|
||||
from enrollment.api import add_enrollment
|
||||
from enrollment.views import EnrollmentCrossDomainSessionAuth
|
||||
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
|
||||
from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser
|
||||
from student.models import CourseEnrollment
|
||||
from util.json_request import JsonResponse
|
||||
@@ -62,6 +63,22 @@ class BasketsView(APIView):
|
||||
""" Enroll the user in the course. """
|
||||
add_enrollment(user.username, unicode(course_key))
|
||||
|
||||
def _handle_marketing_opt_in(self, request, course_key, user):
|
||||
"""
|
||||
Handle the marketing email opt-in flag, if it was set.
|
||||
|
||||
Errors here aren't expected, but should not break the outer enrollment transaction.
|
||||
"""
|
||||
email_opt_in = request.DATA.get('email_opt_in', None)
|
||||
if email_opt_in is not None:
|
||||
try:
|
||||
update_email_opt_in(user, course_key.org, email_opt_in)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# log the error, return silently
|
||||
log.exception(
|
||||
'Failed to handle marketing opt-in flag: user="%s", course="%s"', user.username, course_key
|
||||
)
|
||||
|
||||
def post(self, request, *args, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Attempt to create the basket and enroll the user.
|
||||
@@ -96,6 +113,7 @@ class BasketsView(APIView):
|
||||
username=user.username)
|
||||
log.debug(msg)
|
||||
self._enroll(course_key, user)
|
||||
self._handle_marketing_opt_in(request, course_key, user)
|
||||
return DetailResponse(msg)
|
||||
|
||||
# Setup the API
|
||||
@@ -108,6 +126,8 @@ class BasketsView(APIView):
|
||||
log.debug(msg)
|
||||
return DetailResponse(msg)
|
||||
|
||||
response = None
|
||||
|
||||
# Make the API call
|
||||
try:
|
||||
response_data = api.baskets.post({
|
||||
@@ -118,12 +138,12 @@ class BasketsView(APIView):
|
||||
payment_data = response_data["payment_data"]
|
||||
if payment_data:
|
||||
# Pass data to the client to begin the payment flow.
|
||||
return JsonResponse(payment_data)
|
||||
response = JsonResponse(payment_data)
|
||||
elif response_data['order']:
|
||||
# The order was completed immediately because there is no charge.
|
||||
msg = Messages.ORDER_COMPLETED.format(order_number=response_data['order']['number'])
|
||||
log.debug(msg)
|
||||
return DetailResponse(msg)
|
||||
response = DetailResponse(msg)
|
||||
else:
|
||||
msg = u'Unexpected response from basket endpoint.'
|
||||
log.error(
|
||||
@@ -143,6 +163,9 @@ class BasketsView(APIView):
|
||||
user_id=user.id
|
||||
)
|
||||
|
||||
self._handle_marketing_opt_in(request, course_key, user)
|
||||
return response
|
||||
|
||||
|
||||
class BasketOrderView(APIView):
|
||||
""" Retrieve the order associated with a basket. """
|
||||
|
||||
Reference in New Issue
Block a user