Skip to content

Commit

Permalink
feat!: removes deprecated v1 certificate behavior
Browse files Browse the repository at this point in the history
this removes the long-deprecated v1  certificate behavior. This removes
the old-style date selection behavior  (ie., not a choice between
*Immediately upon passing*, *End date of course*, *A date after the course
end date*), which is no longer reliably maintained or supported in
Studio or Credentials.

FIXES: #35399
  • Loading branch information
deborahgu committed Sep 30, 2024
1 parent 5043260 commit 67e43c2
Show file tree
Hide file tree
Showing 18 changed files with 84 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,3 @@ class CourseSettingsSerializer(serializers.Serializer):
show_min_grade_warning = serializers.BooleanField()
sidebar_html_enabled = serializers.BooleanField()
upgrade_deadline = serializers.DateTimeField(allow_null=True)
use_v2_cert_display_settings = serializers.BooleanField()
2 changes: 0 additions & 2 deletions cms/djangoapps/contentstore/rest_api/v1/views/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ def get(self, request: Request, course_id: str):
"show_min_grade_warning": false,
"sidebar_html_enabled": true,
"upgrade_deadline": null,
"use_v2_cert_display_settings": false
}
```
"""
Expand All @@ -112,7 +111,6 @@ def get(self, request: Request, course_id: str):
'course_display_name_with_default': course_block.display_name_with_default,
'platform_name': settings.PLATFORM_NAME,
'licensing_enabled': settings.FEATURES.get("LICENSING", False),
'use_v2_cert_display_settings': settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS", False),
})

serializer = CourseSettingsSerializer(settings_context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def test_course_settings_response(self):
"show_min_grade_warning": False,
"upgrade_deadline": None,
"licensing_enabled": False,
"use_v2_cert_display_settings": False,
}

self.assertEqual(response.status_code, status.HTTP_200_OK)
Expand Down
11 changes: 0 additions & 11 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,17 +468,6 @@
# .. toggle_tickets: https://github.com/openedx/edx-platform/pull/26106
'ENABLE_HELP_LINK': True,

# .. toggle_name: FEATURES['ENABLE_V2_CERT_DISPLAY_SETTINGS']
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False
# .. toggle_description: Whether to use the reimagined certificates_display_behavior and certificate_available_date
# .. settings. Will eventually become the default.
# .. toggle_use_cases: temporary
# .. toggle_creation_date: 2021-07-26
# .. toggle_target_removal_date: 2021-10-01
# .. toggle_tickets: 'https://openedx.atlassian.net/browse/MICROBA-1405'
'ENABLE_V2_CERT_DISPLAY_SETTINGS': False,

# .. toggle_name: FEATURES['ENABLE_INTEGRITY_SIGNATURE']
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False
Expand Down
68 changes: 27 additions & 41 deletions cms/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
${show_min_grade_warning | n, dump_js_escaped_json},
${can_show_certificate_available_date_field(context_course) | n, dump_js_escaped_json},
"${upgrade_deadline | n, js_escaped_string}",
${settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS") | n, dump_js_escaped_json}
);
});
</%block>
Expand Down Expand Up @@ -251,58 +250,45 @@ <h2 class="title-2">${_('Course Schedule')}</h2>
</li>
</ol>

<%
use_v2_cert_display_settings = settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS", False)
%>
% if can_show_certificate_available_date_field(context_course):
<ol class="list-input">
<li class="field-group field-group-certificate-available" id="certificate-available">
<div class="field date" id="field-certificates-display-behavior">
<label for="certificates-display-behavior">${_("Certificates Display Behavior")}</label>
% if use_v2_cert_display_settings:
<select id="certificates-display-behavior">
<option value="early_no_info">${_("Immediately upon passing")}</option>
<option value="end">${_("End date of course")}</option>
<option value="end_with_date">${_("A date after the course end date")}</option>
</select>
% else:
<input id="certificates-display-behavior" type="text">
% endif
<select id="certificates-display-behavior">
<option value="early_no_info">${_("Immediately upon passing")}</option>
<option value="end">${_("End date of course")}</option>
<option value="end_with_date">${_("A date after the course end date")}</option>
</select>
<span class="tip tip-stacked">${_("Certificates are awarded at the end of a course run")}</span>

% if use_v2_cert_display_settings:
<!-- Collapsible -->
<div class="collapsible">
<div id="certificate-display-behavior-collapsible-trigger" class="collapsible-trigger" role="button" tabindex="0" aria-expanded="false">
<span>
<span class="icon icon-inline fa fa-info-circle" aria-hidden="true"></span>
${_("Read more about this setting")}
</span>
<!-- Collapsible -->
<div class="collapsible">
<div id="certificate-display-behavior-collapsible-trigger" class="collapsible-trigger" role="button" tabindex="0" aria-expanded="false">
<span>
<span class="icon icon-inline fa fa-info-circle" aria-hidden="true"></span>
${_("Read more about this setting")}
</span>
</div>
<div id="certificate-display-behavior-collapsible-content" class="collapsible-content collapsed">
<p>${_("In all configurations of this setting, certificates are generated for learners as soon as they achieve the passing threshold in the course (which can occur before a final assignment based on course design)")}</p>
<div>
<div class="collapsible-description-heading">${_("Immediately upon passing")}</div>
<div class="collapsible-description-description">${_("Learners can access their certificate as soon as they achieve a passing grade above the course grade threshold. Note: learners can achieve a passing grade before encountering all assignments in some course configurations.")}</div>
</div>
<div id="certificate-display-behavior-collapsible-content" class="collapsible-content collapsed">
<p>${_("In all configurations of this setting, certificates are generated for learners as soon as they achieve the passing threshold in the course (which can occur before a final assignment based on course design)")}</p>
<div>
<div class="collapsible-description-heading">${_("Immediately upon passing")}</div>
<div class="collapsible-description-description">${_("Learners can access their certificate as soon as they achieve a passing grade above the course grade threshold. Note: learners can achieve a passing grade before encountering all assignments in some course configurations.")}</div>
</div>
<div>
<div class="collapsible-description-heading">${_("On course end date")}</div>
<div class="collapsible-description-description">${_("Learners with passing grades can access their certificate once the end date of the course has elapsed.")}</div>
</div>
<div>
<div class="collapsible-description-heading">${_("A date after the course end date")}</div>
<div class="collapsible-description-description">${_("Learners with passing grades can access their certificate after the date that you set has elapsed.")}</div>
</div>
<div>
<div class="collapsible-description-heading">${_("On course end date")}</div>
<div class="collapsible-description-description">${_("Learners with passing grades can access their certificate once the end date of the course has elapsed.")}</div>
</div>
<div>
<div class="collapsible-description-heading">${_("A date after the course end date")}</div>
<div class="collapsible-description-description">${_("Learners with passing grades can access their certificate after the date that you set has elapsed.")}</div>
</div>
</div>
% endif
</div>
</div>

% if use_v2_cert_display_settings:
<div class="field date hidden" id="field-certificate-available-date" >
% else:
<div class="field date" id="field-certificate-available-date" >
% endif
<div class="field date hidden" id="field-certificate-available-date" >
<label for="certificate-available-date">${_("Certificates Available Date")}</label>
<input type="text" class="certificate-available-date date start datepicker" id="certificate-available-date" placeholder="MM/DD/YYYY" autocomplete="off" />
<span class="icon icon-inline fa fa-calendar-check-o datepicker-icon" aria-hidden="true"></span>
Expand Down
22 changes: 7 additions & 15 deletions common/djangoapps/student/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,22 +646,14 @@ def _is_certificate_earned_but_not_available(course_overview, status):
(bool): True if the user earned the certificate but it's hidden due to display behavior, else False
"""
if settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS"):
return (
not certificates_viewable_for_course(course_overview)
and CertificateStatuses.is_passing_status(status)
and course_overview.certificates_display_behavior in (
CertificatesDisplayBehaviors.END_WITH_DATE,
CertificatesDisplayBehaviors.END
)
)
else:
return (
not certificates_viewable_for_course(course_overview) and
CertificateStatuses.is_passing_status(status) and
course_overview.certificate_available_date
return (
not certificates_viewable_for_course(course_overview)
and CertificateStatuses.is_passing_status(status)
and course_overview.certificates_display_behavior in (
CertificatesDisplayBehaviors.END_WITH_DATE,
CertificatesDisplayBehaviors.END
)

)

def process_survey_link(survey_link, user):
"""
Expand Down
14 changes: 4 additions & 10 deletions lms/djangoapps/certificates/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,9 @@ def certificate_downloadable_status(student, course_key):

course_overview = get_course_overview_or_none(course_key)

if settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS"):
display_behavior_is_valid = (
course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
)
else:
display_behavior_is_valid = True
display_behavior_is_valid = (
course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
)

if (
not certificates_viewable_for_course(course_overview)
Expand Down Expand Up @@ -837,10 +834,7 @@ def can_show_certificate_message(course, student, course_grade, certificates_ena

def _course_uses_available_date(course):
"""Returns if the course has an certificate_available_date set and that it should be used"""
if settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS"):
display_behavior_is_valid = course.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
else:
display_behavior_is_valid = True
display_behavior_is_valid = course.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE

return (
can_show_certificate_available_date_field(course)
Expand Down
25 changes: 1 addition & 24 deletions lms/djangoapps/certificates/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,28 +209,6 @@ def test_with_downloadable_web_cert(self):
"uuid": cert_status["uuid"],
}

@ddt.data(
(False, timedelta(days=2), False, True),
(False, -timedelta(days=2), True, None),
(True, timedelta(days=2), True, None),
)
@ddt.unpack
@patch.dict(settings.FEATURES, {"CERTIFICATES_HTML_VIEW": True})
@patch.dict(settings.FEATURES, {"ENABLE_V2_CERT_DISPLAY_SETTINGS": False})
def test_cert_api_return_v1(self, self_paced, cert_avail_delta, cert_downloadable_status, earned_but_not_available):
"""
Test 'downloadable status'
"""
cert_avail_date = datetime.now(pytz.UTC) + cert_avail_delta
self.course.self_paced = self_paced
self.course.certificate_available_date = cert_avail_date
self.course.save()

self._setup_course_certificate()

downloadable_status = certificate_downloadable_status(self.student, self.course.id)
assert downloadable_status["is_downloadable"] == cert_downloadable_status
assert downloadable_status.get("earned_but_not_available") == earned_but_not_available

@ddt.data(
(True, timedelta(days=2), CertificatesDisplayBehaviors.END_WITH_DATE, True, None),
Expand All @@ -243,8 +221,7 @@ def test_cert_api_return_v1(self, self_paced, cert_avail_delta, cert_downloadabl
)
@ddt.unpack
@patch.dict(settings.FEATURES, {"CERTIFICATES_HTML_VIEW": True})
@patch.dict(settings.FEATURES, {"ENABLE_V2_CERT_DISPLAY_SETTINGS": True})
def test_cert_api_return_v2(
def test_cert_api_return(
self,
self_paced,
cert_avail_delta,
Expand Down
35 changes: 1 addition & 34 deletions lms/djangoapps/certificates/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,40 +80,7 @@ def test_has_html_certificates_enabled_from_course_overview_disabled(self):
(CertificatesDisplayBehaviors.END, False, False, _LAST_MONTH, True, True),
)
@ddt.unpack
@patch.dict(settings.FEATURES, ENABLE_V2_CERT_DISPLAY_SETTINGS=True)
def test_should_certificate_be_visible_v2(
self,
certificates_display_behavior,
certificates_show_before_end,
has_ended,
certificate_available_date,
self_paced,
expected_value
):
"""Test whether the certificate should be visible to user given multiple usecases"""
assert should_certificate_be_visible(
certificates_display_behavior,
certificates_show_before_end,
has_ended,
certificate_available_date,
self_paced
) == expected_value

@ddt.data(
('early_with_info', True, True, _LAST_MONTH, False, True),
('early_no_info', False, False, _LAST_MONTH, False, True),
('end', True, False, _LAST_MONTH, False, True),
('end', False, True, _LAST_MONTH, False, True),
('end', False, False, _NEXT_WEEK, False, False),
('end', False, False, _LAST_WEEK, False, True),
('end', False, False, None, False, False),
('early_with_info', False, False, None, False, True),
('end', False, False, _NEXT_WEEK, False, False),
('end', False, False, _NEXT_WEEK, True, True),
)
@ddt.unpack
@patch.dict(settings.FEATURES, ENABLE_V2_CERT_DISPLAY_SETTINGS=False)
def test_should_certificate_be_visible_v1(
def test_should_certificate_be_visible(
self,
certificates_display_behavior,
certificates_show_before_end,
Expand Down
37 changes: 13 additions & 24 deletions lms/djangoapps/certificates/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,30 +153,19 @@ def should_certificate_be_visible(
certificate_available_date (datetime): the date the certificate is available on for the course.
self_paced (bool): Whether the course is self-paced.
"""
if settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS"):
show_early = (
certificates_display_behavior == CertificatesDisplayBehaviors.EARLY_NO_INFO
or certificates_show_before_end
)
past_available_date = (
certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
and certificate_available_date
and certificate_available_date < datetime.now(utc)
)
ended_without_available_date = (
certificates_display_behavior == CertificatesDisplayBehaviors.END
and has_ended
)
else:
show_early = (
certificates_display_behavior in ('early_with_info', 'early_no_info')
or certificates_show_before_end
)
past_available_date = (
certificate_available_date
and certificate_available_date < datetime.now(utc)
)
ended_without_available_date = (certificate_available_date is None) and has_ended
show_early = (
certificates_display_behavior == CertificatesDisplayBehaviors.EARLY_NO_INFO
or certificates_show_before_end
)
past_available_date = (
certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
and certificate_available_date
and certificate_available_date < datetime.now(utc)
)
ended_without_available_date = (
certificates_display_behavior == CertificatesDisplayBehaviors.END
and has_ended
)

return any((self_paced, show_early, past_available_date, ended_without_available_date))

Expand Down
36 changes: 15 additions & 21 deletions lms/djangoapps/certificates/views/webview.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,28 +353,22 @@ def _get_user_certificate(request, user, course_key, course_overview, preview_mo
if preview_mode:
# certificate is being previewed from studio
if request.user.has_perm(PREVIEW_CERTIFICATES, course_overview):
if not settings.FEATURES.get("ENABLE_V2_CERT_DISPLAY_SETTINGS"):
if course_overview.certificate_available_date and not course_overview.self_paced:
modified_date = course_overview.certificate_available_date
else:
modified_date = datetime.now().date()
if (
course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
and course_overview.certificate_available_date
and not course_overview.self_paced
):
modified_date = course_overview.certificate_available_date
elif course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END:
modified_date = course_overview.end
else:
if (
course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
and course_overview.certificate_available_date
and not course_overview.self_paced
):
modified_date = course_overview.certificate_available_date
elif course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END:
modified_date = course_overview.end
else:
modified_date = datetime.now().date()
user_certificate = GeneratedCertificate(
mode=preview_mode,
verify_uuid=str(uuid4().hex),
modified_date=modified_date,
created_date=datetime.now().date(),
)
modified_date = datetime.now().date()
user_certificate = GeneratedCertificate(
mode=preview_mode,
verify_uuid=str(uuid4().hex),
modified_date=modified_date,
created_date=datetime.now().date(),
)
elif certificates_viewable_for_course(course_overview):
# certificate is being viewed by learner or public
try:
Expand Down
Loading

0 comments on commit 67e43c2

Please sign in to comment.