AA-197: Provide cert upgrade info to learning MFE

Specifically, pass the MFE the audit access expiration date and
let it know when the upgrade deadline has passed, by not passing
any verified mode information along.
This commit is contained in:
Michael Terry
2020-10-26 14:34:16 -04:00
parent d435c0c29e
commit a4bd5a7ec9
8 changed files with 47 additions and 61 deletions

View File

@@ -28,7 +28,6 @@ from openedx.core.djangoapps.catalog.utils import get_course_run_details
from openedx.core.djangoapps.certificates.api import can_show_certificate_available_date_field from openedx.core.djangoapps.certificates.api import can_show_certificate_available_date_field
from openedx.core.djangolib.markup import HTML, Text from openedx.core.djangolib.markup import HTML, Text
from openedx.features.course_duration_limits.access import get_user_course_expiration_date from openedx.features.course_duration_limits.access import get_user_course_expiration_date
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
from openedx.features.course_experience import RELATIVE_DATES_FLAG, UPGRADE_DEADLINE_MESSAGE, CourseHomeMessages from openedx.features.course_experience import RELATIVE_DATES_FLAG, UPGRADE_DEADLINE_MESSAGE, CourseHomeMessages
from student.models import CourseEnrollment from student.models import CourseEnrollment
@@ -444,8 +443,6 @@ class CourseExpiredDate(DateSummary):
@property @property
def date(self): def date(self):
if not CourseDurationLimitConfig.enabled_for_enrollment(self.user, self.course):
return
return get_user_course_expiration_date(self.user, self.course) return get_user_course_expiration_date(self.user, self.course)
@property @property

View File

@@ -21,7 +21,6 @@ from openedx.core.djangoapps.django_comment_common.models import Role
from openedx.core.djangoapps.schedules.models import Schedule from openedx.core.djangoapps.schedules.models import Schedule
from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace
from openedx.features.course_duration_limits.access import get_user_course_expiration_date, get_user_course_duration from openedx.features.course_duration_limits.access import get_user_course_expiration_date, get_user_course_duration
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
from student.models import CourseEnrollment from student.models import CourseEnrollment
from xmodule.partitions.partitions_service import get_all_partitions_for_course, get_user_partition_groups from xmodule.partitions.partitions_service import get_all_partitions_for_course, get_user_partition_groups
@@ -333,7 +332,8 @@ def get_base_experiment_metadata_context(course, user, enrollment, user_enrollme
user, enrollment, course user, enrollment, course
) )
deadline, duration = get_audit_access_expiration(user, course) duration = get_user_course_duration(user, course)
deadline = duration and get_user_course_expiration_date(user, course)
return { return {
'upgrade_link': upgrade_link, 'upgrade_link': upgrade_link,
@@ -355,16 +355,6 @@ def get_base_experiment_metadata_context(course, user, enrollment, user_enrollme
} }
def get_audit_access_expiration(user, course):
"""
Return the expiration date and course duration for the user's audit access to this course.
"""
if not CourseDurationLimitConfig.enabled_for_enrollment(user, course):
return None, None
return get_user_course_expiration_date(user, course), get_user_course_duration(user, course)
# TODO: clean up as part of REVEM-199 (START) # TODO: clean up as part of REVEM-199 (START)
def get_program_context(course, user_enrollments): def get_program_context(course, user_enrollments):
""" """

View File

@@ -10,7 +10,6 @@ from rest_framework.reverse import reverse
from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.certificates.api import certificate_downloadable_status from lms.djangoapps.certificates.api import certificate_downloadable_status
from openedx.features.course_duration_limits.access import get_user_course_expiration_date from openedx.features.course_duration_limits.access import get_user_course_expiration_date
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
from student.models import CourseEnrollment, User from student.models import CourseEnrollment, User
from util.course import get_encoded_course_sharing_utm_params, get_link_for_about_page from util.course import get_encoded_course_sharing_utm_params, get_link_for_about_page
@@ -96,9 +95,6 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer):
""" """
Returns expiration date for a course audit expiration, if any or null Returns expiration date for a course audit expiration, if any or null
""" """
if not CourseDurationLimitConfig.enabled_for_enrollment(model.user, model.course):
return None
return get_user_course_expiration_date(model.user, model.course) return get_user_course_expiration_date(model.user, model.course)
def get_certificate(self, model): def get_certificate(self, model):

View File

@@ -65,33 +65,12 @@ def can_show_certificate_message(course, student, course_grade, certificates_ena
has_active_enrollment = CourseEnrollment.is_enrolled(student, course.id) has_active_enrollment = CourseEnrollment.is_enrolled(student, course.id)
certificates_are_viewable = certificates_viewable_for_course(course) certificates_are_viewable = certificates_viewable_for_course(course)
# Adding a temporary logging for EDUCATOR-2017. return (
if six.text_type(course.id) == u'course-v1:RITx+PM9004x+3T2017':
log.info(
(
u'can_show_certificate_message called with:'
u'course:%s, student: %s, course grade: %s,'
u'certificates_enabled_for_course: %s, certificates_viewable_for_course: %s, auto_cert_gen_enabled: %s,'
u'has_active_enrollment: %s, passed: %s, is_whitelisted: %s'
),
course.id,
student.username,
course_grade,
certificates_enabled_for_course,
certificates_are_viewable,
auto_cert_gen_enabled,
has_active_enrollment,
course_grade.passed,
is_whitelisted
)
if not (
(auto_cert_gen_enabled or certificates_enabled_for_course) and (auto_cert_gen_enabled or certificates_enabled_for_course) and
has_active_enrollment and has_active_enrollment and
certificates_are_viewable and certificates_are_viewable and
(course_grade.passed or is_whitelisted) (course_grade.passed or is_whitelisted)
): )
return False
return True
def can_show_certificate_available_date_field(course): def can_show_certificate_available_date_field(course):

View File

@@ -41,7 +41,9 @@ from lms.djangoapps.verify_student.services import IDVerificationService
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin
from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG
from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.content_type_gating.models import ContentTypeGatingConfig
from openedx.features.course_duration_limits.access import generate_course_expired_message from openedx.features.course_duration_limits.access import (
get_user_course_expiration_date, generate_course_expired_message
)
from openedx.features.discounts.utils import generate_offer_html from openedx.features.discounts.utils import generate_offer_html
from student.models import CourseEnrollment, CourseEnrollmentCelebration, LinkedInAddToProfileConfiguration from student.models import CourseEnrollment, CourseEnrollmentCelebration, LinkedInAddToProfileConfiguration
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
@@ -135,8 +137,7 @@ class CoursewareMeta:
@property @property
def can_show_upgrade_sock(self): def can_show_upgrade_sock(self):
return (DISPLAY_COURSE_SOCK_FLAG.is_enabled(self.course_key) and return DISPLAY_COURSE_SOCK_FLAG.is_enabled(self.course_key)
can_show_verified_upgrade(self.effective_user, self.enrollment_object))
@property @property
def license(self): def license(self):
@@ -181,15 +182,18 @@ class CoursewareMeta:
""" """
Return verified mode information, or None. Return verified mode information, or None.
""" """
if not can_show_verified_upgrade(self.effective_user, self.enrollment_object):
return None
mode = CourseMode.verified_mode_for_course(self.course_key) mode = CourseMode.verified_mode_for_course(self.course_key)
if mode: return {
return { 'access_expiration_date': get_user_course_expiration_date(self.effective_user, self.overview),
'price': mode.min_price, 'price': mode.min_price,
'currency': mode.currency.upper(), 'currency': mode.currency.upper(),
'currency_symbol': get_currency_symbol(mode.currency.upper()), 'currency_symbol': get_currency_symbol(mode.currency.upper()),
'sku': mode.sku, 'sku': mode.sku,
'upgrade_url': verified_upgrade_deadline_link(self.effective_user, self.overview), 'upgrade_url': verified_upgrade_deadline_link(self.effective_user, self.overview),
} }
@property @property
def notes(self): def notes(self):

View File

@@ -62,6 +62,8 @@ def get_user_course_duration(user, course):
- Course access duration is bounded by the min and max duration. - Course access duration is bounded by the min and max duration.
- If course fields are missing, default course access duration to MIN_DURATION. - If course fields are missing, default course access duration to MIN_DURATION.
""" """
if not CourseDurationLimitConfig.enabled_for_enrollment(user, course):
return None
enrollment = CourseEnrollment.get_enrollment(user, course.id) enrollment = CourseEnrollment.get_enrollment(user, course.id)
if enrollment is None or enrollment.mode != CourseMode.AUDIT: if enrollment is None or enrollment.mode != CourseMode.AUDIT:
@@ -107,9 +109,6 @@ def check_course_expired(user, course):
if get_course_masquerade(user, course.id): if get_course_masquerade(user, course.id):
return ACCESS_GRANTED return ACCESS_GRANTED
if not CourseDurationLimitConfig.enabled_for_enrollment(user, course):
return ACCESS_GRANTED
expiration_date = get_user_course_expiration_date(user, course) expiration_date = get_user_course_expiration_date(user, course)
if expiration_date and timezone.now() > expiration_date: if expiration_date and timezone.now() > expiration_date:
return AuditExpiredError(user, course, expiration_date) return AuditExpiredError(user, course, expiration_date)
@@ -127,9 +126,6 @@ def generate_course_expired_message(user, course):
""" """
Generate the message for the user course expiration date if it exists. Generate the message for the user course expiration date if it exists.
""" """
if not CourseDurationLimitConfig.enabled_for_enrollment(user, course):
return
expiration_date = get_user_course_expiration_date(user, course) expiration_date = get_user_course_expiration_date(user, course)
if not expiration_date: if not expiration_date:
return return

View File

@@ -43,6 +43,7 @@ from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID
# pylint: disable=no-member
@ddt.ddt @ddt.ddt
class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin): class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin):
"""Tests to verify the get_user_course_expiration_date function is working correctly""" """Tests to verify the get_user_course_expiration_date function is working correctly"""
@@ -96,6 +97,11 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin):
self.course.self_paced = True self.course.self_paced = True
mock_get_course_run_details.return_value = {'weeks_to_complete': weeks_to_complete} mock_get_course_run_details.return_value = {'weeks_to_complete': weeks_to_complete}
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.AUDIT) enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.AUDIT)
CourseDurationLimitConfig.objects.create(
enabled=True,
course=CourseOverview.get_from_id(self.course.id),
enabled_as_of=self.course.start,
)
result = get_user_course_expiration_date( result = get_user_course_expiration_date(
self.user, self.user,
CourseOverview.get_from_id(self.course.id), CourseOverview.get_from_id(self.course.id),
@@ -114,12 +120,18 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin):
start_date = now() - timedelta(weeks=10) start_date = now() - timedelta(weeks=10)
past_course = CourseFactory(start=start_date) past_course = CourseFactory(start=start_date)
enrollment = CourseEnrollment.enroll(self.user, past_course.id, CourseMode.AUDIT) enrollment = CourseEnrollment.enroll(self.user, past_course.id, CourseMode.AUDIT)
CourseDurationLimitConfig.objects.create(
enabled=True,
course=CourseOverview.get_from_id(past_course.id),
enabled_as_of=past_course.start,
)
result = get_user_course_expiration_date( result = get_user_course_expiration_date(
self.user, self.user,
CourseOverview.get_from_id(past_course.id), CourseOverview.get_from_id(past_course.id),
) )
self.assertEqual(result, None) self.assertEqual(result, None)
add_course_mode(past_course, mode_slug=CourseMode.AUDIT)
add_course_mode(past_course, upgrade_deadline_expired=False) add_course_mode(past_course, upgrade_deadline_expired=False)
result = get_user_course_expiration_date( result = get_user_course_expiration_date(
self.user, self.user,
@@ -132,12 +144,18 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin):
start_date = now() + timedelta(weeks=10) start_date = now() + timedelta(weeks=10)
future_course = CourseFactory(start=start_date) future_course = CourseFactory(start=start_date)
enrollment = CourseEnrollment.enroll(self.user, future_course.id, CourseMode.AUDIT) enrollment = CourseEnrollment.enroll(self.user, future_course.id, CourseMode.AUDIT)
CourseDurationLimitConfig.objects.create(
enabled=True,
course=CourseOverview.get_from_id(future_course.id),
enabled_as_of=past_course.start,
)
result = get_user_course_expiration_date( result = get_user_course_expiration_date(
self.user, self.user,
CourseOverview.get_from_id(future_course.id), CourseOverview.get_from_id(future_course.id),
) )
self.assertEqual(result, None) self.assertEqual(result, None)
add_course_mode(future_course, mode_slug=CourseMode.AUDIT)
add_course_mode(future_course, upgrade_deadline_expired=False) add_course_mode(future_course, upgrade_deadline_expired=False)
result = get_user_course_expiration_date( result = get_user_course_expiration_date(
self.user, self.user,
@@ -157,6 +175,12 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin):
start_date = now() - timedelta(weeks=10) start_date = now() - timedelta(weeks=10)
course = CourseFactory(start=start_date) course = CourseFactory(start=start_date)
enrollment = CourseEnrollment.enroll(self.user, course.id, CourseMode.AUDIT) enrollment = CourseEnrollment.enroll(self.user, course.id, CourseMode.AUDIT)
CourseDurationLimitConfig.objects.create(
enabled=True,
course=CourseOverview.get_from_id(course.id),
enabled_as_of=course.start,
)
add_course_mode(course, mode_slug=CourseMode.AUDIT)
add_course_mode(course, upgrade_deadline_expired=True) add_course_mode(course, upgrade_deadline_expired=True)
result = get_user_course_expiration_date( result = get_user_course_expiration_date(
self.user, self.user,

View File

@@ -2,6 +2,6 @@
set -e set -e
export LOWER_PYLINT_THRESHOLD=1000 export LOWER_PYLINT_THRESHOLD=1000
export UPPER_PYLINT_THRESHOLD=2500 export UPPER_PYLINT_THRESHOLD=2430
export ESLINT_THRESHOLD=5530 export ESLINT_THRESHOLD=5300
export STYLELINT_THRESHOLD=880 export STYLELINT_THRESHOLD=880