Commit fb905e54 by Calen Pennington Committed by GitHub

Merge pull request #15709 from edx/release-mergeback-to-master

Merge release back to master
parents 903bb6ab 68df7b80
......@@ -12,6 +12,7 @@ from django.db import models
from django.db.models import Q
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
from request_cache.middleware import RequestCache, ns_request_cached
......@@ -693,6 +694,59 @@ def invalidate_course_mode_cache(sender, **kwargs): # pylint: disable=unused-a
RequestCache.clear_request_cache(name=CourseMode.CACHE_NAMESPACE)
def get_cosmetic_verified_display_price(course):
"""
Returns the minimum verified cert course price as a string preceded by correct currency, or 'Free'.
"""
return get_course_prices(course, verified_only=True)[1]
def get_cosmetic_display_price(course):
"""
Returns the course price as a string preceded by correct currency, or 'Free'.
"""
return get_course_prices(course)[1]
def get_course_prices(course, verified_only=False):
"""
Return registration_price and cosmetic_display_prices.
registration_price is the minimum price for the course across all course modes.
cosmetic_display_prices is the course price as a string preceded by correct currency, or 'Free'.
"""
# Find the
if verified_only:
registration_price = CourseMode.min_course_price_for_verified_for_currency(
course.id,
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
)
else:
registration_price = CourseMode.min_course_price_for_currency(
course.id,
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
)
currency_symbol = settings.PAID_COURSE_REGISTRATION_CURRENCY[1]
if registration_price > 0:
price = registration_price
# Handle course overview objects which have no cosmetic_display_price
elif hasattr(course, 'cosmetic_display_price'):
price = course.cosmetic_display_price
else:
price = None
if price:
# Translators: This will look like '$50', where {currency_symbol} is a symbol such as '$' and {price} is a
# numerical amount in that currency. Adjust this display as needed for your language.
cosmetic_display_price = _("{currency_symbol}{price}").format(currency_symbol=currency_symbol, price=price)
else:
# Translators: This refers to the cost of the course. In this case, the course costs nothing so it is free.
cosmetic_display_price = _('Free')
return registration_price, force_text(cosmetic_display_price)
class CourseModesArchive(models.Model):
"""
Store the past values of course_mode that a course had in the past. We decided on having
......
......@@ -11,13 +11,18 @@ from datetime import datetime, timedelta
import ddt
import pytz
from django.core.exceptions import ValidationError
from django.test import TestCase
from django.test import TestCase, override_settings
from mock import patch
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from opaque_keys.edx.locator import CourseLocator
from course_modes.helpers import enrollment_mode_display
from course_modes.models import CourseMode, Mode, invalidate_course_mode_cache
from course_modes.models import CourseMode, Mode, invalidate_course_mode_cache, get_cosmetic_display_price
from course_modes.tests.factories import CourseModeFactory
from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.django_utils import (
ModuleStoreTestCase,
)
@ddt.ddt
......@@ -474,3 +479,26 @@ class CourseModeModelTest(TestCase):
self.assertTrue(is_error_expected, "Did not expect a ValidationError to be thrown.")
else:
self.assertFalse(is_error_expected, "Expected a ValidationError to be thrown.")
class TestDisplayPrices(ModuleStoreTestCase):
@override_settings(PAID_COURSE_REGISTRATION_CURRENCY=["USD", "$"])
def test_get_cosmetic_display_price(self):
"""
Check that get_cosmetic_display_price() returns the correct price given its inputs.
"""
course = CourseFactory.create()
registration_price = 99
course.cosmetic_display_price = 10
with patch('course_modes.models.CourseMode.min_course_price_for_currency', return_value=registration_price):
# Since registration_price is set, it overrides the cosmetic_display_price and should be returned
self.assertEqual(get_cosmetic_display_price(course), "$99")
registration_price = 0
with patch('course_modes.models.CourseMode.min_course_price_for_currency', return_value=registration_price):
# Since registration_price is not set, cosmetic_display_price should be returned
self.assertEqual(get_cosmetic_display_price(course), "$10")
course.cosmetic_display_price = 0
# Since both prices are not set, there is no price, thus "Free"
self.assertEqual(get_cosmetic_display_price(course), "Free")
......@@ -23,6 +23,7 @@ from course_modes.models import CourseMode
from courseware.access import has_access
from edxmako.shortcuts import render_to_response
from lms.djangoapps.commerce.utils import EcommerceService
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
from openedx.core.djangoapps.embargo import api as embargo_api
from openedx.features.enterprise_support import api as enterprise_api
from student.models import CourseEnrollment
......@@ -151,6 +152,13 @@ class ChooseModeView(View):
"responsive": True,
"nav_hidden": True,
}
context.update(
get_experiment_user_metadata_context(
request,
course,
request.user,
)
)
title_content = _("Congratulations! You are now enrolled in {course_name}").format(
course_name=course.display_name_with_default_escaped
......
......@@ -237,18 +237,18 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase):
# # of sql queries to default,
# # of mongo queries,
# )
('no_overrides', 1, True, False): (23, 1),
('no_overrides', 2, True, False): (23, 1),
('no_overrides', 3, True, False): (23, 1),
('ccx', 1, True, False): (23, 1),
('ccx', 2, True, False): (23, 1),
('ccx', 3, True, False): (23, 1),
('no_overrides', 1, False, False): (23, 1),
('no_overrides', 2, False, False): (23, 1),
('no_overrides', 3, False, False): (23, 1),
('ccx', 1, False, False): (23, 1),
('ccx', 2, False, False): (23, 1),
('ccx', 3, False, False): (23, 1),
('no_overrides', 1, True, False): (24, 1),
('no_overrides', 2, True, False): (24, 1),
('no_overrides', 3, True, False): (24, 1),
('ccx', 1, True, False): (24, 1),
('ccx', 2, True, False): (24, 1),
('ccx', 3, True, False): (24, 1),
('no_overrides', 1, False, False): (24, 1),
('no_overrides', 2, False, False): (24, 1),
('no_overrides', 3, False, False): (24, 1),
('ccx', 1, False, False): (24, 1),
('ccx', 2, False, False): (24, 1),
('ccx', 3, False, False): (24, 1),
}
......@@ -260,19 +260,19 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase):
__test__ = True
TEST_DATA = {
('no_overrides', 1, True, False): (23, 3),
('no_overrides', 2, True, False): (23, 3),
('no_overrides', 3, True, False): (23, 3),
('ccx', 1, True, False): (23, 3),
('ccx', 2, True, False): (23, 3),
('ccx', 3, True, False): (23, 3),
('ccx', 1, True, True): (24, 3),
('ccx', 2, True, True): (24, 3),
('ccx', 3, True, True): (24, 3),
('no_overrides', 1, False, False): (23, 3),
('no_overrides', 2, False, False): (23, 3),
('no_overrides', 3, False, False): (23, 3),
('ccx', 1, False, False): (23, 3),
('ccx', 2, False, False): (23, 3),
('ccx', 3, False, False): (23, 3),
('no_overrides', 1, True, False): (24, 3),
('no_overrides', 2, True, False): (24, 3),
('no_overrides', 3, True, False): (24, 3),
('ccx', 1, True, False): (24, 3),
('ccx', 2, True, False): (24, 3),
('ccx', 3, True, False): (24, 3),
('ccx', 1, True, True): (25, 3),
('ccx', 2, True, True): (25, 3),
('ccx', 3, True, True): (25, 3),
('no_overrides', 1, False, False): (24, 3),
('no_overrides', 2, False, False): (24, 3),
('no_overrides', 3, False, False): (24, 3),
('ccx', 1, False, False): (24, 3),
('ccx', 2, False, False): (24, 3),
('ccx', 3, False, False): (24, 3),
}
......@@ -388,7 +388,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
self.assertEqual(resp.status_code, 200)
def test_num_queries_instructor_paced(self):
self.fetch_course_info_with_queries(self.instructor_paced_course, 25, 3)
self.fetch_course_info_with_queries(self.instructor_paced_course, 26, 3)
def test_num_queries_self_paced(self):
self.fetch_course_info_with_queries(self.self_paced_course, 25, 3)
self.fetch_course_info_with_queries(self.self_paced_course, 26, 3)
......@@ -211,8 +211,8 @@ class IndexQueryTestCase(ModuleStoreTestCase):
NUM_PROBLEMS = 20
@ddt.data(
(ModuleStoreEnum.Type.mongo, 10, 144),
(ModuleStoreEnum.Type.split, 4, 144),
(ModuleStoreEnum.Type.mongo, 10, 145),
(ModuleStoreEnum.Type.split, 4, 145),
)
@ddt.unpack
def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count):
......@@ -577,26 +577,6 @@ class ViewsTestCase(ModuleStoreTestCase):
response = self.client.get(request_url)
self.assertEqual(response.status_code, 404)
@override_settings(PAID_COURSE_REGISTRATION_CURRENCY=["USD", "$"])
def test_get_cosmetic_display_price(self):
"""
Check that get_cosmetic_display_price() returns the correct price given its inputs.
"""
registration_price = 99
self.course.cosmetic_display_price = 10
with patch('course_modes.models.CourseMode.min_course_price_for_currency', return_value=registration_price):
# Since registration_price is set, it overrides the cosmetic_display_price and should be returned
self.assertEqual(views.get_cosmetic_display_price(self.course), "$99")
registration_price = 0
with patch('course_modes.models.CourseMode.min_course_price_for_currency', return_value=registration_price):
# Since registration_price is not set, cosmetic_display_price should be returned
self.assertEqual(views.get_cosmetic_display_price(self.course), "$10")
self.course.cosmetic_display_price = 0
# Since both prices are not set, there is no price, thus "Free"
self.assertEqual(views.get_cosmetic_display_price(self.course), "Free")
def test_jump_to_invalid(self):
# TODO add a test for invalid location
# TODO add a test for no data *
......@@ -1464,12 +1444,12 @@ class ProgressPageTests(ProgressPageBaseTests):
"""Test that query counts remain the same for self-paced and instructor-paced courses."""
SelfPacedConfiguration(enabled=self_paced_enabled).save()
self.setup_course(self_paced=self_paced)
with self.assertNumQueries(40, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST), check_mongo_calls(1):
with self.assertNumQueries(41, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST), check_mongo_calls(1):
self._get_progress_page()
@ddt.data(
(False, 40, 26),
(True, 33, 22)
(False, 41, 27),
(True, 34, 23)
)
@ddt.unpack
def test_progress_queries(self, enable_waffle, initial, subsequent):
......
......@@ -22,6 +22,7 @@ from web_fragments.fragment import Fragment
from edxmako.shortcuts import render_to_response, render_to_string
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
from lms.djangoapps.gating.api import get_entrance_exam_score_ratio, get_entrance_exam_usage_key
from lms.djangoapps.grades.new.course_grade_factory import CourseGradeFactory
from openedx.core.djangoapps.crawlers.models import CrawlersConfig
......@@ -34,6 +35,7 @@ from openedx.features.course_experience.views.course_sock import CourseSockFragm
from openedx.features.enterprise_support.api import data_sharing_consent_required
from shoppingcart.models import CourseRegistrationCode
from student.views import is_course_blocked
from student.models import CourseEnrollment
from util.views import ensure_valid_course_key
from xmodule.modulestore.django import modulestore
from xmodule.x_module import STUDENT_VIEW
......@@ -52,8 +54,6 @@ from ..model_data import FieldDataCache
from ..module_render import get_module_for_descriptor, toc_for_course
from .views import (
CourseTabView,
check_and_get_upgrade_link,
get_cosmetic_verified_display_price
)
log = logging.getLogger("edx.courseware.views.index")
......@@ -325,6 +325,7 @@ class CoursewareIndex(View):
"""
course_url_name = default_course_url_name(self.course.id)
course_url = reverse(course_url_name, kwargs={'course_id': unicode(self.course.id)})
courseware_context = {
'csrf': csrf(self.request)['csrf_token'],
'course': self.course,
......@@ -344,11 +345,14 @@ class CoursewareIndex(View):
'section_title': None,
'sequence_title': None,
'disable_accordion': COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
'upgrade_link': check_and_get_upgrade_link(request, self.effective_user, self.course.id),
'upgrade_price': get_cosmetic_verified_display_price(self.course),
# ENDTODO
}
courseware_context.update(
get_experiment_user_metadata_context(
request,
self.course,
self.effective_user,
)
)
table_of_contents = toc_for_course(
self.effective_user,
self.request,
......
......@@ -14,7 +14,7 @@ import waffle
from certificates import api as certs_api
from certificates.models import CertificateStatuses
from commerce.utils import EcommerceService
from course_modes.models import CourseMode
from course_modes.models import (CourseMode, get_course_prices)
from courseware.access import has_access, has_ccx_coach_role
from courseware.access_utils import check_course_open_for_learner
from courseware.courses import (
......@@ -61,6 +61,7 @@ from ipware.ip import get_ip
from lms.djangoapps.ccx.custom_exception import CCXLocatorValidationException
from lms.djangoapps.ccx.utils import prep_course_for_grading
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect, Redirect
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
from lms.djangoapps.grades.new.course_grade_factory import CourseGradeFactory
from lms.djangoapps.instructor.enrollment import uses_shib
from lms.djangoapps.instructor.views.api import require_global_staff
......@@ -322,13 +323,14 @@ def course_info(request, course_id):
'dates_fragment': dates_fragment,
'url_to_enroll': CourseTabView.url_to_enroll(course_key),
'course_tools': course_tools,
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
'upgrade_link': check_and_get_upgrade_link(request, user, course.id),
'upgrade_price': get_cosmetic_verified_display_price(course),
'course_tools': course_tools,
# ENDTODO
}
context.update(
get_experiment_user_metadata_context(
request,
course,
user,
)
)
# Get the URL of the user's last position in order to display the 'where you were last' message
context['resume_course_url'] = None
......@@ -348,20 +350,6 @@ def course_info(request, course_id):
UPGRADE_COOKIE_NAME = 'show_upgrade_notification'
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
def check_and_get_upgrade_link(request, user, course_id):
upgrade_link = None
if request.user.is_authenticated():
upgrade_data = VerifiedUpgradeDeadlineDate(None, user, course_id=course_id)
if upgrade_data.is_enabled:
upgrade_link = upgrade_data.link
request.need_to_set_upgrade_cookie = True
return upgrade_link
# ENDTODO
class StaticCourseTabView(EdxFragmentView):
"""
View that displays a static course tab with a given name.
......@@ -521,7 +509,8 @@ class CourseTabView(EdxFragmentView):
# Disable student view button if user is staff and
# course is not yet visible to students.
supports_preview_menu = False
return {
context = {
'course': course,
'tab': tab,
'active_page': tab.get('type', None),
......@@ -530,11 +519,15 @@ class CourseTabView(EdxFragmentView):
'supports_preview_menu': supports_preview_menu,
'uses_pattern_library': True,
'disable_courseware_js': True,
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
'upgrade_link': check_and_get_upgrade_link(request, request.user, course.id),
'upgrade_price': get_cosmetic_verified_display_price(course),
# ENDTODO
}
context.update(
get_experiment_user_metadata_context(
request,
course,
request.user,
)
)
return context
def render_to_fragment(self, request, course=None, page_context=None, **kwargs):
"""
......@@ -585,59 +578,6 @@ def registered_for_course(course, user):
return False
def get_cosmetic_verified_display_price(course):
"""
Returns the minimum verified cert course price as a string preceded by correct currency, or 'Free'.
"""
return get_course_prices(course, verified_only=True)[1]
def get_cosmetic_display_price(course):
"""
Returns the course price as a string preceded by correct currency, or 'Free'.
"""
return get_course_prices(course)[1]
def get_course_prices(course, verified_only=False):
"""
Return registration_price and cosmetic_display_prices.
registration_price is the minimum price for the course across all course modes.
cosmetic_display_prices is the course price as a string preceded by correct currency, or 'Free'.
"""
# Find the
if verified_only:
registration_price = CourseMode.min_course_price_for_verified_for_currency(
course.id,
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
)
else:
registration_price = CourseMode.min_course_price_for_currency(
course.id,
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
)
currency_symbol = settings.PAID_COURSE_REGISTRATION_CURRENCY[1]
if registration_price > 0:
price = registration_price
# Handle course overview objects which have no cosmetic_display_price
elif hasattr(course, 'cosmetic_display_price'):
price = course.cosmetic_display_price
else:
price = None
if price:
# Translators: This will look like '$50', where {currency_symbol} is a symbol such as '$' and {price} is a
# numerical amount in that currency. Adjust this display as needed for your language.
cosmetic_display_price = _("{currency_symbol}{price}").format(currency_symbol=currency_symbol, price=price)
else:
# Translators: This refers to the cost of the course. In this case, the course costs nothing so it is free.
cosmetic_display_price = _('Free')
return registration_price, cosmetic_display_price
class EnrollStaffView(View):
"""
Displays view for registering in the course to a global staff user.
......@@ -927,7 +867,6 @@ def _progress(request, course_key, student_id):
grade_summary = course_grade.summary
studio_url = get_studio_url(course, 'settings/grading')
# checking certificate generation configuration
enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(student, course_key)
......@@ -943,11 +882,14 @@ def _progress(request, course_key, student_id):
'passed': is_course_passed(course, grade_summary),
'credit_course_requirements': _credit_course_requirements(course_key, student),
'certificate_data': _get_cert_data(student, course, course_key, is_active, enrollment_mode),
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
'upgrade_link': check_and_get_upgrade_link(request, student, course.id),
'upgrade_price': get_cosmetic_verified_display_price(course),
# ENDTODO
}
context.update(
get_experiment_user_metadata_context(
request,
course,
student,
)
)
with outer_atomic():
response = render_to_response('courseware/progress.html', context)
......
......@@ -24,6 +24,7 @@ from rest_framework import status
from web_fragments.fragment import Fragment
import django_comment_client.utils as utils
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
import lms.lib.comment_client as cc
from courseware.access import has_access
from courseware.courses import get_course_with_access
......@@ -44,7 +45,6 @@ from django_comment_client.utils import (
strip_none
)
from django_comment_common.utils import ThreadContext, get_course_discussion_settings, set_course_discussion_settings
from lms.djangoapps.courseware.views.views import check_and_get_upgrade_link, get_cosmetic_verified_display_price
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from student.models import CourseEnrollment
from util.json_request import JsonResponse, expect_json
......@@ -481,13 +481,16 @@ def _create_discussion_board_context(request, base_context, thread=None):
'category_map': course_settings["category_map"],
'course_settings': course_settings,
'is_commentable_divided': is_commentable_divided(course_key, discussion_id, course_discussion_settings),
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
'upgrade_link': check_and_get_upgrade_link(request, user, course.id),
'upgrade_price': get_cosmetic_verified_display_price(course),
# ENDTODO
# If the default topic id is None the front-end code will look for a topic that contains "General"
'discussion_default_topic_id': _get_discussion_default_topic_id(course),
})
context.update(
get_experiment_user_metadata_context(
request,
course,
user,
)
)
return context
......
from student.models import CourseEnrollment
from course_modes.models import (
get_cosmetic_verified_display_price
)
from courseware.date_summary import (
VerifiedUpgradeDeadlineDate
)
def check_and_get_upgrade_link(request, user, course_id):
"""
For an authenticated user, return a link to allow them to upgrade
in the specified course.
"""
if request.user.is_authenticated():
upgrade_data = VerifiedUpgradeDeadlineDate(None, user, course_id=course_id)
if upgrade_data.is_enabled:
request.need_to_set_upgrade_cookie = True
return upgrade_data
return None
def get_experiment_user_metadata_context(request, course, user):
"""
Return a context dictionary with the keys used by the user_metadata.html.
"""
enrollment_mode = None
enrollment_time = None
try:
enrollment = CourseEnrollment.objects.get(user_id=user.id, course_id=course.id)
if enrollment.is_active:
enrollment_mode = enrollment.mode
enrollment_time = enrollment.created
except CourseEnrollment.DoesNotExist:
pass # Not enrolled, used the default None values
upgrade_data = check_and_get_upgrade_link(request, user, course.id)
return {
'upgrade_link': upgrade_data and upgrade_data.link,
'upgrade_price': get_cosmetic_verified_display_price(course),
'enrollment_mode': enrollment_mode,
'enrollment_time': enrollment_time,
'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
'upgrade_deadline': upgrade_data and upgrade_data.date,
'course_key': course.id,
'course_start': course.start,
'course_end': course.end,
}
......@@ -104,6 +104,7 @@ from pipeline_mako import render_require_js_path_overrides
<%block name="head_extra"/>
<%include file="/courseware/experiments.html"/>
<%include file="user_metadata.html"/>
<%static:optional_include_mako file="head-extra.html" is_theming_enabled="True" />
<%include file="widgets/optimizely.html" />
......
<%page expression_filter="h"/>
<%!
from openedx.core.djangolib.js_utils import dump_js_escaped_json
from eventtracking import tracker
from opaque_keys.edx.keys import CourseKey
%>
<%
user_metadata = {
key: context.get(key)
for key in (
'username',
'user_id',
'course_id',
'enrollment_mode',
'upgrade_link',
'upgrade_price',
'pacing_type',
)
}
if user:
user_metadata['username'] = user.username
user_metadata['user_id'] = user.id
for datekey in (
'schedule_start',
'enrollment_time',
'course_start',
'course_end',
'upgrade_deadline'
):
user_metadata[datekey] = (
context.get(datekey).isoformat() if context.get(datekey) else None
)
course_key = context.get('course_key')
if course and not course_key:
course_key = course.id
if course_key:
if isinstance(course_key, CourseKey):
user_metadata['course_key_fields'] = {
'org': course_key.org,
'course': course_key.course,
'run': course_key.run,
}
if not course_id:
user_metadata['course_id'] = unicode(course_key)
elif isinstance(course_key, basestring):
user_metadata['course_id'] = course_key
%>
<script type="application/json" id="user-metadata">
${user_metadata | n, dump_js_escaped_json}
</script>
......@@ -160,7 +160,7 @@ class TestCourseHomePage(CourseHomePageTestCase):
course_home_url(self.course)
# Fetch the view and verify the query counts
with self.assertNumQueries(40, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with self.assertNumQueries(41, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with check_mongo_calls(4):
url = course_home_url(self.course)
self.client.get(url)
......
......@@ -127,7 +127,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
course_updates_url(self.course)
# Fetch the view and verify that the query counts haven't changed
with self.assertNumQueries(31, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with self.assertNumQueries(32, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with check_mongo_calls(4):
url = course_updates_url(self.course)
self.client.get(url)
......@@ -6,9 +6,8 @@ from opaque_keys.edx.keys import CourseKey
from web_fragments.fragment import Fragment
from student.models import CourseEnrollment
from course_modes.models import CourseMode
from course_modes.models import CourseMode, get_cosmetic_verified_display_price
from courseware.date_summary import VerifiedUpgradeDeadlineDate
from courseware.views.views import get_cosmetic_verified_display_price
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
......
......@@ -2392,7 +2392,7 @@ class MakoTemplateLinter(BaseLinter):
contexts = [{'index': 0, 'type': 'html'}]
javascript_types = [
'text/javascript', 'text/ecmascript', 'application/ecmascript', 'application/javascript',
'text/x-mathjax-config', 'json/xblock-args'
'text/x-mathjax-config', 'json/xblock-args', 'application/json',
]
html_types = ['text/template']
for context in contexts_re.finditer(mako_template):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment