TNL-7185: Send data, not rendered HTML to the learning MFE

Specifically, send data versions of course_expired_message and
offer_html.

The rendered HTML is still being sent for now, until the learning
MFE is updated to consume the data objects.
This commit is contained in:
Michael Terry
2020-12-11 09:27:27 -05:00
parent 0c57a02119
commit eef72b5ab7
11 changed files with 354 additions and 136 deletions

View File

@@ -109,6 +109,7 @@ class OutlineTabSerializer(DatesBannerSerializerMixin, VerifiedModeSerializerMix
"""
Serializer for the Outline Tab
"""
access_expiration = serializers.DictField()
course_blocks = CourseBlockSerializer()
course_expired_html = serializers.CharField()
course_goals = CourseGoalsSerializer()
@@ -117,6 +118,7 @@ class OutlineTabSerializer(DatesBannerSerializerMixin, VerifiedModeSerializerMix
enroll_alert = EnrollAlertSerializer()
handouts_html = serializers.CharField()
has_ended = serializers.BooleanField()
offer = serializers.DictField()
offer_html = serializers.CharField()
resume_course = ResumeCourseSerializer()
welcome_message_html = serializers.CharField()

View File

@@ -22,6 +22,7 @@ from openedx.features.course_duration_limits.models import CourseDurationLimitCo
from openedx.features.course_experience import (
COURSE_ENABLE_UNENROLLED_ACCESS_FLAG, DISPLAY_COURSE_SOCK_FLAG, ENABLE_COURSE_GOALS,
)
from openedx.features.discounts.applicability import DISCOUNT_APPLICABILITY_FLAG
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import UserFactory
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE
@@ -165,17 +166,37 @@ class OutlineTabTestViews(BaseCourseHomeTests):
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_OUTLINE_TAB, active=True)
@patch('lms.djangoapps.course_home_api.outline.v1.views.generate_offer_html', new=Mock(return_value='<p>Offer</p>'))
def test_offer_html(self):
def test_offer(self):
CourseEnrollment.enroll(self.user, self.course.id)
self.assertEqual(self.client.get(self.url).data['offer_html'], '<p>Offer</p>')
response = self.client.get(self.url)
self.assertIsNone(response.data['offer'])
self.assertIsNone(response.data['offer_html'])
with override_waffle_flag(DISCOUNT_APPLICABILITY_FLAG, active=True):
response = self.client.get(self.url)
self.assertIsNotNone(response.data['offer_html'])
# Just a quick spot check that the dictionary looks like what we expect
self.assertEqual(response.data['offer']['code'], 'EDXWELCOME')
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_OUTLINE_TAB, active=True)
@patch('lms.djangoapps.course_home_api.outline.v1.views.generate_course_expired_message', new=Mock(return_value='<p>Expired</p>'))
def test_course_expired_html(self):
CourseEnrollment.enroll(self.user, self.course.id)
self.assertEqual(self.client.get(self.url).data['course_expired_html'], '<p>Expired</p>')
def test_access_expiration(self):
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))
response = self.client.get(self.url)
self.assertIsNone(response.data['access_expiration'])
self.assertIsNone(response.data['course_expired_html'])
enrollment.update_enrollment(CourseMode.AUDIT)
response = self.client.get(self.url)
self.assertIsNotNone(response.data['course_expired_html'])
# Just a quick spot check that the dictionary looks like what we expect
deadline = enrollment.created + MIN_DURATION
self.assertEqual(response.data['access_expiration']['expiration_date'], deadline)
@override_waffle_flag(ENABLE_COURSE_GOALS, active=True)
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)

View File

@@ -30,14 +30,14 @@ from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course
from lms.djangoapps.courseware.date_summary import TodaysDate
from lms.djangoapps.courseware.masquerade import setup_masquerade
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.features.course_duration_limits.access import generate_course_expired_message
from openedx.features.course_duration_limits.access import generate_course_expired_message, get_access_expiration_data
from openedx.features.course_experience import COURSE_ENABLE_UNENROLLED_ACCESS_FLAG
from openedx.features.course_experience.course_tools import CourseToolsPluginManager
from openedx.features.course_experience.course_updates import (
dismiss_current_update_for_user, get_current_update_for_user,
)
from openedx.features.course_experience.utils import get_course_outline_block_tree
from openedx.features.discounts.utils import generate_offer_html
from openedx.features.discounts.utils import generate_offer_data, generate_offer_html
from common.djangoapps.student.models import CourseEnrollment
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE
from xmodule.modulestore.django import modulestore
@@ -69,6 +69,11 @@ class OutlineTabView(RetrieveAPIView):
Body consists of the following fields:
access_expiration: An object detailing when access to this course will expire
expiration_date: (str) When the access expires, in ISO 8601 notation
masquerading_expired_course: (bool) Whether this course is expired for the masqueraded user
upgrade_deadline: (str) Last chance to upgrade, in ISO 8601 notation (or None if can't upgrade anymore)
upgrade_url: (str) Upgrade linke (or None if can't upgrade anymore)
course_blocks:
blocks: List of serialized Course Block objects. Each serialization has the following fields:
id: (str) The usage ID of the block.
@@ -114,6 +119,13 @@ class OutlineTabView(RetrieveAPIView):
extra_text: (str)
handouts_html: (str) Raw HTML for the handouts section of the course info
has_ended: (bool) Indicates whether course has ended
offer: An object detailing upgrade discount information
code: (str) Checkout code
expiration_date: (str) Expiration of offer, in ISO 8601 notation
original_price: (str) Full upgrade price without checkout code; includes currency symbol
discounted_price: (str) Upgrade price with checkout code; includes currency symbol
percentage: (int) Amount of discount
upgrade_url: (str) Checkout URL
resume_course:
has_visited_course: (bool) Whether the user has ever visited the course
url: (str) The display name of the course block to resume
@@ -165,7 +177,9 @@ class OutlineTabView(RetrieveAPIView):
handouts_html = get_course_info_section(request, request.user, course, 'handouts') if show_handouts else ''
# TODO: TNL-7185 Legacy: Refactor to return the offer & expired data and format the message in the MFE
offer_data = show_enrolled and generate_offer_data(request.user, course_overview)
offer_html = show_enrolled and generate_offer_html(request.user, course_overview)
access_expiration = show_enrolled and get_access_expiration_data(request.user, course_overview)
course_expired_html = show_enrolled and generate_course_expired_message(request.user, course_overview)
welcome_message_html = show_enrolled and get_current_update_for_user(request, course)
@@ -243,6 +257,7 @@ class OutlineTabView(RetrieveAPIView):
}
data = {
'access_expiration': access_expiration or None,
'course_blocks': course_blocks,
'course_expired_html': course_expired_html or None,
'course_goals': course_goals,
@@ -251,6 +266,7 @@ class OutlineTabView(RetrieveAPIView):
'enroll_alert': enroll_alert,
'handouts_html': handouts_html or None,
'has_ended': course.has_ended(),
'offer': offer_data or None,
'offer_html': offer_html or None,
'resume_course': resume_course,
'welcome_message_html': welcome_message_html or None,

View File

@@ -269,8 +269,8 @@ class IndexQueryTestCase(ModuleStoreTestCase):
NUM_PROBLEMS = 20
@ddt.data(
(ModuleStoreEnum.Type.mongo, 10, 171),
(ModuleStoreEnum.Type.split, 4, 167),
(ModuleStoreEnum.Type.mongo, 10, 173),
(ModuleStoreEnum.Type.split, 4, 169),
)
@ddt.unpack
def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count):