harden down access to the shoppingcart if the ENABLE_PAID_COURSE_REGISTRATION flag is not set (either via the main Django configuration settings) or through microsite overrides
This commit is contained in:
@@ -265,6 +265,7 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@patch('courseware.views.log.warning')
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
|
||||
def test_blocked_course_scenario(self, log_warning):
|
||||
|
||||
self.client.login(username="jack", password="test")
|
||||
|
||||
@@ -49,6 +49,7 @@ from xmodule.tabs import CourseTabList, StaffGradingTab, PeerGradingTab, OpenEnd
|
||||
from xmodule.x_module import STUDENT_VIEW
|
||||
import shoppingcart
|
||||
from shoppingcart.models import CourseRegistrationCode
|
||||
from shoppingcart.utils import is_shopping_cart_enabled
|
||||
from opaque_keys import InvalidKeyError
|
||||
|
||||
from microsite_configuration import microsite
|
||||
@@ -731,8 +732,8 @@ def course_about(request, course_id):
|
||||
registration_price = 0
|
||||
in_cart = False
|
||||
reg_then_add_to_cart_link = ""
|
||||
if (settings.FEATURES.get('ENABLE_SHOPPING_CART') and
|
||||
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')):
|
||||
|
||||
if (is_shopping_cart_enabled()):
|
||||
registration_price = CourseMode.min_course_price_for_currency(course_key,
|
||||
settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
|
||||
if request.user.is_authenticated():
|
||||
|
||||
@@ -1604,6 +1604,7 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase
|
||||
|
||||
@ddt.ddt
|
||||
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
|
||||
class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
"""
|
||||
Test endpoints that show data without side effects.
|
||||
|
||||
@@ -5,9 +5,8 @@ navigation. We want to do this in the context_processor 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
|
||||
from microsite_configuration import microsite
|
||||
|
||||
|
||||
def user_has_cart_context_processor(request):
|
||||
@@ -19,16 +18,8 @@ def user_has_cart_context_processor(request):
|
||||
display_shopping_cart = (
|
||||
# user is logged in and
|
||||
request.user.is_authenticated() and
|
||||
# settings enable paid course reg
|
||||
microsite.get_value(
|
||||
'ENABLE_PAID_COURSE_REGISTRATION',
|
||||
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')
|
||||
) and
|
||||
# settings enable shopping cart
|
||||
microsite.get_value(
|
||||
'ENABLE_SHOPPING_CART',
|
||||
settings.FEATURES.get('ENABLE_SHOPPING_CART')
|
||||
) and
|
||||
# do we have the feature turned on
|
||||
shoppingcart.utils.is_shopping_cart_enabled() and
|
||||
# user's cart has PaidCourseRegistrations
|
||||
shoppingcart.models.Order.user_cart_has_items(
|
||||
request.user,
|
||||
|
||||
22
lms/djangoapps/shoppingcart/decorators.py
Normal file
22
lms/djangoapps/shoppingcart/decorators.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
This file defines any decorators used by the shopping cart app
|
||||
"""
|
||||
|
||||
from django.http import Http404
|
||||
from .utils import is_shopping_cart_enabled
|
||||
|
||||
|
||||
def enforce_shopping_cart_enabled(func):
|
||||
"""
|
||||
Is a decorator that forces a wrapped method to be run in a runtime
|
||||
which has the ENABLE_SHOPPING_CART flag set
|
||||
"""
|
||||
def func_wrapper(*args, **kwargs):
|
||||
"""
|
||||
Wrapper function that does the enforcement that
|
||||
the shopping cart feature is enabled
|
||||
"""
|
||||
if not is_shopping_cart_enabled():
|
||||
raise Http404
|
||||
return func(*args, **kwargs)
|
||||
return func_wrapper
|
||||
@@ -64,6 +64,7 @@ MODULESTORE_CONFIG = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}, incl
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=MODULESTORE_CONFIG)
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
|
||||
class ShoppingCartViewsTests(ModuleStoreTestCase):
|
||||
def setUp(self):
|
||||
patcher = patch('student.models.tracker')
|
||||
@@ -963,8 +964,36 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
|
||||
((template, _context), _tmp) = render_mock.call_args
|
||||
self.assertEqual(template, cert_item.single_item_receipt_template)
|
||||
|
||||
def _assert_404(self, url, use_post=False):
|
||||
"""
|
||||
Helper method to assert that a given url will return a 404 status code
|
||||
"""
|
||||
if use_post:
|
||||
response = self.client.post(url)
|
||||
else:
|
||||
response = self.client.get(url)
|
||||
self.assertEquals(response.status_code, 404)
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': False})
|
||||
def test_disabled_paid_courses(self):
|
||||
"""
|
||||
Assert that the pages that require ENABLE_PAID_COURSE_REGISTRATION=True return a
|
||||
HTTP 404 status code when we have this flag turned off
|
||||
"""
|
||||
self.login_user()
|
||||
self._assert_404(reverse('shoppingcart.views.show_cart', args=[]))
|
||||
self._assert_404(reverse('shoppingcart.views.clear_cart', args=[]))
|
||||
self._assert_404(reverse('shoppingcart.views.remove_item', args=[]), use_post=True)
|
||||
self._assert_404(reverse('shoppingcart.views.register_code_redemption', args=["testing"]))
|
||||
self._assert_404(reverse('shoppingcart.views.use_code', args=[]), use_post=True)
|
||||
self._assert_404(reverse('shoppingcart.views.update_user_cart', args=[]))
|
||||
self._assert_404(reverse('shoppingcart.views.reset_code_redemption', args=[]), use_post=True)
|
||||
self._assert_404(reverse('shoppingcart.views.billing_details', args=[]))
|
||||
self._assert_404(reverse('shoppingcart.views.register_courses', args=[]))
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=MODULESTORE_CONFIG)
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
|
||||
class RegistrationCodeRedemptionCourseEnrollment(ModuleStoreTestCase):
|
||||
"""
|
||||
Test suite for RegistrationCodeRedemption Course Enrollments
|
||||
|
||||
@@ -6,23 +6,19 @@ urlpatterns = patterns('shoppingcart.views', # nopep8
|
||||
url(r'^receipt/(?P<ordernum>[0-9]*)/$', 'show_receipt'),
|
||||
url(r'^donation/$', 'donate', name='donation'),
|
||||
url(r'^csv_report/$', 'csv_report', name='payment_csv_report'),
|
||||
# These following URLs are only valid if the ENABLE_SHOPPING_CART feature flag is set
|
||||
url(r'^$', 'show_cart'),
|
||||
url(r'^clear/$', 'clear_cart'),
|
||||
url(r'^remove_item/$', 'remove_item'),
|
||||
url(r'^add/course/{}/$'.format(settings.COURSE_ID_PATTERN), 'add_course_to_cart', name='add_course_to_cart'),
|
||||
url(r'^register/redeem/(?P<registration_code>[0-9A-Za-z]+)/$', 'register_code_redemption', name='register_code_redemption'),
|
||||
url(r'^use_code/$', 'use_code'),
|
||||
url(r'^update_user_cart/$', 'update_user_cart'),
|
||||
url(r'^reset_code_redemption/$', 'reset_code_redemption'),
|
||||
url(r'^billing_details/$', 'billing_details', name='billing_details'),
|
||||
url(r'^register_courses/$', 'register_courses'),
|
||||
)
|
||||
|
||||
if settings.FEATURES['ENABLE_SHOPPING_CART']:
|
||||
urlpatterns += patterns(
|
||||
'shoppingcart.views',
|
||||
url(r'^$', 'show_cart'),
|
||||
url(r'^clear/$', 'clear_cart'),
|
||||
url(r'^remove_item/$', 'remove_item'),
|
||||
url(r'^add/course/{}/$'.format(settings.COURSE_ID_PATTERN), 'add_course_to_cart', name='add_course_to_cart'),
|
||||
url(r'^register/redeem/(?P<registration_code>[0-9A-Za-z]+)/$', 'register_code_redemption', name='register_code_redemption'),
|
||||
url(r'^use_code/$', 'use_code'),
|
||||
url(r'^update_user_cart/$', 'update_user_cart'),
|
||||
url(r'^reset_code_redemption/$', 'reset_code_redemption'),
|
||||
url(r'^billing_details/$', 'billing_details', name='billing_details'),
|
||||
url(r'^register_courses/$', 'register_courses'),
|
||||
)
|
||||
|
||||
if settings.FEATURES.get('ENABLE_PAYMENT_FAKE'):
|
||||
from shoppingcart.tests.payment_fake import PaymentFakeView
|
||||
urlpatterns += patterns(
|
||||
|
||||
24
lms/djangoapps/shoppingcart/utils.py
Normal file
24
lms/djangoapps/shoppingcart/utils.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Utility methods for the Shopping Cart app
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from microsite_configuration import microsite
|
||||
|
||||
|
||||
def is_shopping_cart_enabled():
|
||||
"""
|
||||
Utility method to check the various configuration to verify that
|
||||
all of the settings have been enabled
|
||||
"""
|
||||
enable_paid_course_registration = microsite.get_value(
|
||||
'ENABLE_PAID_COURSE_REGISTRATION',
|
||||
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')
|
||||
)
|
||||
|
||||
enable_shopping_cart = microsite.get_value(
|
||||
'ENABLE_SHOPPING_CART',
|
||||
settings.FEATURES.get('ENABLE_SHOPPING_CART')
|
||||
)
|
||||
|
||||
return (enable_paid_course_registration and enable_shopping_cart)
|
||||
@@ -33,7 +33,7 @@ from .exceptions import (
|
||||
)
|
||||
from .models import (
|
||||
Order, OrderTypes,
|
||||
PaidCourseRegistration, OrderItem, Coupon, CourseRegCodeItem,
|
||||
PaidCourseRegistration, OrderItem, Coupon,
|
||||
CouponRedemption, CourseRegistrationCode, RegistrationCodeRedemption,
|
||||
Donation, DonationConfiguration
|
||||
)
|
||||
@@ -44,6 +44,7 @@ from .processors import (
|
||||
|
||||
import json
|
||||
from xmodule_django.models import CourseKeyField
|
||||
from .decorators import enforce_shopping_cart_enabled
|
||||
|
||||
log = logging.getLogger("shoppingcart")
|
||||
AUDIT_LOG = logging.getLogger("audit")
|
||||
@@ -94,6 +95,7 @@ def add_course_to_cart(request, course_id):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def update_user_cart(request):
|
||||
"""
|
||||
when user change the number-of-students from the UI then
|
||||
@@ -127,6 +129,7 @@ def update_user_cart(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def show_cart(request):
|
||||
"""
|
||||
This view shows cart items.
|
||||
@@ -158,6 +161,7 @@ def show_cart(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def clear_cart(request):
|
||||
cart = Order.get_cart_for_user(request.user)
|
||||
cart.clear()
|
||||
@@ -175,6 +179,7 @@ def clear_cart(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def remove_item(request):
|
||||
"""
|
||||
This will remove an item from the user cart and also delete the corresponding coupon codes redemption.
|
||||
@@ -227,6 +232,7 @@ def remove_code_redemption(order_item_course_id, item_id, item, user):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def reset_code_redemption(request):
|
||||
"""
|
||||
This method reset the code redemption from user cart items.
|
||||
@@ -239,6 +245,7 @@ def reset_code_redemption(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def use_code(request):
|
||||
"""
|
||||
This method may generate the discount against valid coupon code
|
||||
@@ -291,6 +298,7 @@ def get_reg_code_validity(registration_code, request, limiter):
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def register_code_redemption(request, registration_code):
|
||||
"""
|
||||
This view allows the student to redeem the registration code
|
||||
@@ -382,6 +390,7 @@ def use_coupon_code(coupons, user):
|
||||
|
||||
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def register_courses(request):
|
||||
"""
|
||||
This method enroll the user for available course(s)
|
||||
@@ -518,6 +527,7 @@ def postpay_callback(request):
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
@enforce_shopping_cart_enabled
|
||||
def billing_details(request):
|
||||
"""
|
||||
This is the view for capturing additional billing details
|
||||
|
||||
Reference in New Issue
Block a user