diff --git a/lms/djangoapps/shoppingcart/middleware.py b/lms/djangoapps/shoppingcart/middleware.py new file mode 100644 index 0000000000..44f968ce34 --- /dev/null +++ b/lms/djangoapps/shoppingcart/middleware.py @@ -0,0 +1,31 @@ +""" +This is the shoppingcart middleware class. +Currently the only middleware is detects whether request.user has a cart that should be displayed in the +navigation. We want to do this in the middleware to +1) keep database accesses out of templates (this led to a transaction bug with user email changes) +2) because navigation.html is "called" by being included in other templates, there's no "views.py" to put this. +""" +from django.conf import settings +import shoppingcart + +class UserHasCartMiddleware(object): + """ + Detects whether request.user has a cart and sets it as part of the request + + *** + Because this relies on request.user, it needs to enabled in settings after + django.contrib.auth.middleware.AuthenticationMiddleware (or equivalent) + *** + """ + def process_request(self, request): + """ + Checks if request has an authenticated user. If so, checks if request.user has a cart that should + be displayed. Anonymous users don't. + """ + request.display_shopping_cart = False + if (request.user.is_authenticated() and # user exists + settings.MITX_FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION') and # settings are set + settings.MITX_FEATURES.get('ENABLE_SHOPPING_CART') and + shoppingcart.models.Order.user_cart_has_items(request.user)): # user's cart is non-empty + request.display_shopping_cart = True + return None \ No newline at end of file diff --git a/lms/djangoapps/shoppingcart/tests/test_middleware.py b/lms/djangoapps/shoppingcart/tests/test_middleware.py new file mode 100644 index 0000000000..0f124e6e66 --- /dev/null +++ b/lms/djangoapps/shoppingcart/tests/test_middleware.py @@ -0,0 +1,80 @@ +""" +Unit tests for shoppingcart middleware +""" +from mock import patch, Mock +from django.conf import settings +from django.contrib.auth.models import AnonymousUser +from django.test.utils import override_settings + +from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory +from student.tests.factories import UserFactory +from course_modes.models import CourseMode +from shoppingcart.models import Order, PaidCourseRegistration +from shoppingcart.middleware import UserHasCartMiddleware + +@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +class UserCartMiddlewareUnitTest(ModuleStoreTestCase): + def setUp(self): + self.user = UserFactory.create() + self.request = Mock() + self.mw = UserHasCartMiddleware() + + def add_to_cart(self): + course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course') + course_mode = CourseMode(course_id=course.id, + mode_slug="honor", + mode_display_name="honor cert", + min_price=40) + course_mode.save() + cart = Order.get_cart_for_user(self.user) + PaidCourseRegistration.add_to_order(cart, course.id) + + @patch.dict(settings.MITX_FEATURES, {'ENABLE_SHOPPING_CART': False, 'ENABLE_PAID_COURSE_REGISTRATION': True}) + def test_no_enable_shoppingcart(self): + """ + Tests when MITX_FEATURES['ENABLE_SHOPPING_CART'] is not set + """ + self.add_to_cart() + self.request.user = self.user + self.mw.process_request(self.request) + self.assertFalse(self.request.display_shopping_cart) + + @patch.dict(settings.MITX_FEATURES, {'ENABLE_SHOPPING_CART': True, 'ENABLE_PAID_COURSE_REGISTRATION': False}) + def test_no_enable_paid_course_registration(self): + """ + Tests when MITX_FEATURES['ENABLE_PAID_COURSE_REGISTRATION'] is not set + """ + self.add_to_cart() + self.request.user = self.user + self.mw.process_request(self.request) + self.assertFalse(self.request.display_shopping_cart) + + @patch.dict(settings.MITX_FEATURES, {'ENABLE_SHOPPING_CART': True, 'ENABLE_PAID_COURSE_REGISTRATION': True}) + def test_anonymous_user(self): + """ + Tests when request.user is anonymous + """ + self.request.user = AnonymousUser() + self.mw.process_request(self.request) + self.assertFalse(self.request.display_shopping_cart) + + @patch.dict(settings.MITX_FEATURES, {'ENABLE_SHOPPING_CART': True, 'ENABLE_PAID_COURSE_REGISTRATION': True}) + def test_no_items_in_cart(self): + """ + Tests when request.user doesn't have a cart with items + """ + self.request.user = self.user + self.mw.process_request(self.request) + self.assertFalse(self.request.display_shopping_cart) + + @patch.dict(settings.MITX_FEATURES, {'ENABLE_SHOPPING_CART': True, 'ENABLE_PAID_COURSE_REGISTRATION': True}) + def test_items_in_cart(self): + """ + Tests when request.user has a cart with items + """ + self.add_to_cart() + self.request.user = self.user + self.mw.process_request(self.request) + self.assertTrue(self.request.display_shopping_cart) diff --git a/lms/envs/common.py b/lms/envs/common.py index db66b821ca..15ff00eeaf 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -610,6 +610,9 @@ MIDDLEWARE_CLASSES = ( # For A/B testing 'waffle.middleware.WaffleMiddleware', + + # Shoppingcart middleware (detects if request.user has a cart) + 'shoppingcart.middleware.UserHasCartMiddleware', ) ############################### Pipeline ####################################### diff --git a/lms/templates/navigation.html b/lms/templates/navigation.html index e2e1d9d664..7f38561b3c 100644 --- a/lms/templates/navigation.html +++ b/lms/templates/navigation.html @@ -9,8 +9,6 @@ from django.utils.translation import ugettext as _ import branding # app that handles site status messages from status.status import get_site_status_msg -# shopping cart -import shoppingcart %> ## Provide a hook for themes to inject branding on top. @@ -83,9 +81,7 @@ site_status_msg = get_site_status_msg(course_id) - % if settings.MITX_FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION') and \ - settings.MITX_FEATURES.get('ENABLE_SHOPPING_CART') and \ - shoppingcart.models.Order.user_cart_has_items(user): + % if getattr(request, 'display_shopping_cart', False): # see shoppingcart.middleware.UserHasCartMiddleware