From a4bd5a7ec997ce2e2d249add995f394bd162a2a3 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Mon, 26 Oct 2020 14:34:16 -0400 Subject: [PATCH] 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. --- lms/djangoapps/courseware/date_summary.py | 3 --- lms/djangoapps/experiments/utils.py | 14 ++-------- .../mobile_api/users/serializers.py | 4 --- openedx/core/djangoapps/certificates/api.py | 25 ++---------------- .../core/djangoapps/courseware_api/views.py | 26 +++++++++++-------- .../features/course_duration_limits/access.py | 8 ++---- .../tests/test_course_expiration.py | 24 +++++++++++++++++ scripts/thresholds.sh | 4 +-- 8 files changed, 47 insertions(+), 61 deletions(-) diff --git a/lms/djangoapps/courseware/date_summary.py b/lms/djangoapps/courseware/date_summary.py index 3479dd45b0..7ec0c406bd 100644 --- a/lms/djangoapps/courseware/date_summary.py +++ b/lms/djangoapps/courseware/date_summary.py @@ -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.djangolib.markup import HTML, Text 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 student.models import CourseEnrollment @@ -444,8 +443,6 @@ class CourseExpiredDate(DateSummary): @property def date(self): - if not CourseDurationLimitConfig.enabled_for_enrollment(self.user, self.course): - return return get_user_course_expiration_date(self.user, self.course) @property diff --git a/lms/djangoapps/experiments/utils.py b/lms/djangoapps/experiments/utils.py index 3d954da94e..4d4ea98bbf 100644 --- a/lms/djangoapps/experiments/utils.py +++ b/lms/djangoapps/experiments/utils.py @@ -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.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.models import CourseDurationLimitConfig from student.models import CourseEnrollment 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 ) - 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 { '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) def get_program_context(course, user_enrollments): """ diff --git a/lms/djangoapps/mobile_api/users/serializers.py b/lms/djangoapps/mobile_api/users/serializers.py index f64fc52fc4..94a152b6da 100644 --- a/lms/djangoapps/mobile_api/users/serializers.py +++ b/lms/djangoapps/mobile_api/users/serializers.py @@ -10,7 +10,6 @@ from rest_framework.reverse import reverse from lms.djangoapps.courseware.access import has_access 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.models import CourseDurationLimitConfig from student.models import CourseEnrollment, User 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 """ - if not CourseDurationLimitConfig.enabled_for_enrollment(model.user, model.course): - return None - return get_user_course_expiration_date(model.user, model.course) def get_certificate(self, model): diff --git a/openedx/core/djangoapps/certificates/api.py b/openedx/core/djangoapps/certificates/api.py index 3da7de7312..0ae6dec631 100644 --- a/openedx/core/djangoapps/certificates/api.py +++ b/openedx/core/djangoapps/certificates/api.py @@ -65,33 +65,12 @@ def can_show_certificate_message(course, student, course_grade, certificates_ena has_active_enrollment = CourseEnrollment.is_enrolled(student, course.id) certificates_are_viewable = certificates_viewable_for_course(course) - # Adding a temporary logging for EDUCATOR-2017. - 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 ( + return ( (auto_cert_gen_enabled or certificates_enabled_for_course) and has_active_enrollment and certificates_are_viewable and (course_grade.passed or is_whitelisted) - ): - return False - return True + ) def can_show_certificate_available_date_field(course): diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py index 3c8f9f4b85..adc479db63 100644 --- a/openedx/core/djangoapps/courseware_api/views.py +++ b/openedx/core/djangoapps/courseware_api/views.py @@ -41,7 +41,9 @@ from lms.djangoapps.verify_student.services import IDVerificationService from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG 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 student.models import CourseEnrollment, CourseEnrollmentCelebration, LinkedInAddToProfileConfiguration from xmodule.modulestore.django import modulestore @@ -135,8 +137,7 @@ class CoursewareMeta: @property def can_show_upgrade_sock(self): - return (DISPLAY_COURSE_SOCK_FLAG.is_enabled(self.course_key) and - can_show_verified_upgrade(self.effective_user, self.enrollment_object)) + return DISPLAY_COURSE_SOCK_FLAG.is_enabled(self.course_key) @property def license(self): @@ -181,15 +182,18 @@ class CoursewareMeta: """ 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) - if mode: - return { - 'price': mode.min_price, - 'currency': mode.currency.upper(), - 'currency_symbol': get_currency_symbol(mode.currency.upper()), - 'sku': mode.sku, - 'upgrade_url': verified_upgrade_deadline_link(self.effective_user, self.overview), - } + return { + 'access_expiration_date': get_user_course_expiration_date(self.effective_user, self.overview), + 'price': mode.min_price, + 'currency': mode.currency.upper(), + 'currency_symbol': get_currency_symbol(mode.currency.upper()), + 'sku': mode.sku, + 'upgrade_url': verified_upgrade_deadline_link(self.effective_user, self.overview), + } @property def notes(self): diff --git a/openedx/features/course_duration_limits/access.py b/openedx/features/course_duration_limits/access.py index cf40ef2de6..1ae26cc381 100644 --- a/openedx/features/course_duration_limits/access.py +++ b/openedx/features/course_duration_limits/access.py @@ -62,6 +62,8 @@ def get_user_course_duration(user, course): - Course access duration is bounded by the min and max 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) 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): return ACCESS_GRANTED - if not CourseDurationLimitConfig.enabled_for_enrollment(user, course): - return ACCESS_GRANTED - expiration_date = get_user_course_expiration_date(user, course) if expiration_date and timezone.now() > 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. """ - if not CourseDurationLimitConfig.enabled_for_enrollment(user, course): - return - expiration_date = get_user_course_expiration_date(user, course) if not expiration_date: return diff --git a/openedx/features/course_duration_limits/tests/test_course_expiration.py b/openedx/features/course_duration_limits/tests/test_course_expiration.py index 3607997600..d05d46f0e5 100644 --- a/openedx/features/course_duration_limits/tests/test_course_expiration.py +++ b/openedx/features/course_duration_limits/tests/test_course_expiration.py @@ -43,6 +43,7 @@ from xmodule.modulestore.tests.factories import CourseFactory from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID +# pylint: disable=no-member @ddt.ddt class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin): """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 mock_get_course_run_details.return_value = {'weeks_to_complete': weeks_to_complete} 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( self.user, CourseOverview.get_from_id(self.course.id), @@ -114,12 +120,18 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin): start_date = now() - timedelta(weeks=10) past_course = CourseFactory(start=start_date) 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( self.user, CourseOverview.get_from_id(past_course.id), ) self.assertEqual(result, None) + add_course_mode(past_course, mode_slug=CourseMode.AUDIT) add_course_mode(past_course, upgrade_deadline_expired=False) result = get_user_course_expiration_date( self.user, @@ -132,12 +144,18 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin): start_date = now() + timedelta(weeks=10) future_course = CourseFactory(start=start_date) 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( self.user, CourseOverview.get_from_id(future_course.id), ) self.assertEqual(result, None) + add_course_mode(future_course, mode_slug=CourseMode.AUDIT) add_course_mode(future_course, upgrade_deadline_expired=False) result = get_user_course_expiration_date( self.user, @@ -157,6 +175,12 @@ class CourseExpirationTestCase(ModuleStoreTestCase, MasqueradeMixin): start_date = now() - timedelta(weeks=10) course = CourseFactory(start=start_date) 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) result = get_user_course_expiration_date( self.user, diff --git a/scripts/thresholds.sh b/scripts/thresholds.sh index 52dac4f8b4..0676305432 100755 --- a/scripts/thresholds.sh +++ b/scripts/thresholds.sh @@ -2,6 +2,6 @@ set -e export LOWER_PYLINT_THRESHOLD=1000 -export UPPER_PYLINT_THRESHOLD=2500 -export ESLINT_THRESHOLD=5530 +export UPPER_PYLINT_THRESHOLD=2430 +export ESLINT_THRESHOLD=5300 export STYLELINT_THRESHOLD=880