Commit 038d5182 by Sofiya Semenova Committed by GitHub

Merge pull request #15922 from edx/ssemenova/ed-1101

"View/Request Certificate" button logic on progress page and dashboard
parents ae44f184 f3f7e78e
...@@ -1570,6 +1570,7 @@ class ProgressPageTests(ProgressPageBaseTests): ...@@ -1570,6 +1570,7 @@ class ProgressPageTests(ProgressPageBaseTests):
'lms.djangoapps.grades.new.course_grade.CourseGrade.summary', 'lms.djangoapps.grades.new.course_grade.CourseGrade.summary',
PropertyMock(return_value={'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': {}}) PropertyMock(return_value={'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': {}})
) )
@patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True))
def test_message_for_audit_mode(self): def test_message_for_audit_mode(self):
""" Verify that message appears on progress page, if learner is enrolled """ Verify that message appears on progress page, if learner is enrolled
in audit mode. in audit mode.
...@@ -1584,6 +1585,7 @@ class ProgressPageTests(ProgressPageBaseTests): ...@@ -1584,6 +1585,7 @@ class ProgressPageTests(ProgressPageBaseTests):
u'You are enrolled in the audit track for this course. The audit track does not include a certificate.' u'You are enrolled in the audit track for this course. The audit track does not include a certificate.'
) )
@patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True))
def test_invalidated_cert_data(self): def test_invalidated_cert_data(self):
""" """
Verify that invalidated cert data is returned if cert is invalidated. Verify that invalidated cert data is returned if cert is invalidated.
...@@ -1602,6 +1604,7 @@ class ProgressPageTests(ProgressPageBaseTests): ...@@ -1602,6 +1604,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self.assertEqual(response.cert_status, 'invalidated') self.assertEqual(response.cert_status, 'invalidated')
self.assertEqual(response.title, 'Your certificate has been invalidated') self.assertEqual(response.title, 'Your certificate has been invalidated')
@patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True))
def test_downloadable_get_cert_data(self): def test_downloadable_get_cert_data(self):
""" """
Verify that downloadable cert data is returned if cert is downloadable. Verify that downloadable cert data is returned if cert is downloadable.
...@@ -1616,6 +1619,7 @@ class ProgressPageTests(ProgressPageBaseTests): ...@@ -1616,6 +1619,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self.assertEqual(response.cert_status, 'downloadable') self.assertEqual(response.cert_status, 'downloadable')
self.assertEqual(response.title, 'Your certificate is available') self.assertEqual(response.title, 'Your certificate is available')
@patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True))
def test_generating_get_cert_data(self): def test_generating_get_cert_data(self):
""" """
Verify that generating cert data is returned if cert is generating. Verify that generating cert data is returned if cert is generating.
...@@ -1630,6 +1634,7 @@ class ProgressPageTests(ProgressPageBaseTests): ...@@ -1630,6 +1634,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self.assertEqual(response.cert_status, 'generating') self.assertEqual(response.cert_status, 'generating')
self.assertEqual(response.title, "We're working on it...") self.assertEqual(response.title, "We're working on it...")
@patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True))
def test_unverified_get_cert_data(self): def test_unverified_get_cert_data(self):
""" """
Verify that unverified cert data is returned if cert is unverified. Verify that unverified cert data is returned if cert is unverified.
...@@ -1644,6 +1649,7 @@ class ProgressPageTests(ProgressPageBaseTests): ...@@ -1644,6 +1649,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self.assertEqual(response.cert_status, 'unverified') self.assertEqual(response.cert_status, 'unverified')
self.assertEqual(response.title, "Certificate unavailable") self.assertEqual(response.title, "Certificate unavailable")
@patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True))
def test_request_get_cert_data(self): def test_request_get_cert_data(self):
""" """
Verify that requested cert data is returned if cert is to be requested. Verify that requested cert data is returned if cert is to be requested.
......
...@@ -77,6 +77,7 @@ from openedx.core.djangoapps.credit.api import ( ...@@ -77,6 +77,7 @@ from openedx.core.djangoapps.credit.api import (
is_credit_course, is_credit_course,
is_user_eligible_for_credit is_user_eligible_for_credit
) )
from openedx.core.djangoapps.certificates.config import waffle as certificates_waffle
from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.core.djangoapps.models.course_details import CourseDetails
from openedx.core.djangoapps.monitoring_utils import set_custom_metrics_for_course_key from openedx.core.djangoapps.monitoring_utils import set_custom_metrics_for_course_key
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
...@@ -886,9 +887,8 @@ def _progress(request, course_key, student_id): ...@@ -886,9 +887,8 @@ def _progress(request, course_key, student_id):
'masquerade': masquerade, 'masquerade': masquerade,
'supports_preview_menu': True, 'supports_preview_menu': True,
'student': student, 'student': student,
'passed': is_course_passed(course, grade_summary),
'credit_course_requirements': _credit_course_requirements(course_key, student), 'credit_course_requirements': _credit_course_requirements(course_key, student),
'certificate_data': _get_cert_data(student, course, course_key, is_active, enrollment_mode), 'certificate_data': _get_cert_data(student, course, course_key, is_active, enrollment_mode, grade_summary),
} }
context.update( context.update(
get_experiment_user_metadata_context( get_experiment_user_metadata_context(
...@@ -903,7 +903,7 @@ def _progress(request, course_key, student_id): ...@@ -903,7 +903,7 @@ def _progress(request, course_key, student_id):
return response return response
def _get_cert_data(student, course, course_key, is_active, enrollment_mode): def _get_cert_data(student, course, course_key, is_active, enrollment_mode, grade_summary=None):
"""Returns students course certificate related data. """Returns students course certificate related data.
Arguments: Arguments:
...@@ -912,13 +912,14 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): ...@@ -912,13 +912,14 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
course_key (CourseKey): Course identifier for course. course_key (CourseKey): Course identifier for course.
is_active (Bool): Boolean value to check if course is active. is_active (Bool): Boolean value to check if course is active.
enrollment_mode (String): Course mode in which student is enrolled. enrollment_mode (String): Course mode in which student is enrolled.
grade_summary (dict): Student grade details.
Returns: Returns:
returns dict if course certificate is available else None. returns dict if course certificate is available else None.
""" """
from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.courseware.courses import get_course_by_id
if enrollment_mode == CourseMode.AUDIT: if not CourseMode.is_eligible_for_certificate(enrollment_mode):
return CertData( return CertData(
CertificateStatuses.audit_passing, CertificateStatuses.audit_passing,
_('Your enrollment: Audit track'), _('Your enrollment: Audit track'),
...@@ -931,14 +932,22 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): ...@@ -931,14 +932,22 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
if course_key: if course_key:
may_view_certificate = get_course_by_id(course_key).may_certify() may_view_certificate = get_course_by_id(course_key).may_certify()
show_message = all([ switches = certificates_waffle.waffle()
switches_enabled = (switches.is_enabled(certificates_waffle.SELF_PACED_ONLY) and
switches.is_enabled(certificates_waffle.INSTRUCTOR_PACED_ONLY))
student_cert_generation_enabled = certs_api.cert_generation_enabled(course_key) if not switches_enabled else True
# Don't show certificate information if:
# 1) the learner has not passed the course
# 2) the course is not active
# 3) auto-generated certs flags are not enabled, but student cert generation is not enabled either
# 4) the learner may not view the certificate, based on the course's advanced course settings.
if not all([
is_course_passed(course, grade_summary),
is_active, is_active,
CourseMode.is_eligible_for_certificate(enrollment_mode), student_cert_generation_enabled,
certs_api.cert_generation_enabled(course_key),
may_view_certificate may_view_certificate
]) ]):
if not show_message:
return None return None
if certs_api.is_certificate_invalid(student, course_key): if certs_api.is_certificate_invalid(student, course_key):
...@@ -952,24 +961,7 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): ...@@ -952,24 +961,7 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
cert_downloadable_status = certs_api.certificate_downloadable_status(student, course_key) cert_downloadable_status = certs_api.certificate_downloadable_status(student, course_key)
if cert_downloadable_status['is_downloadable']: generating_certificate_message = CertData(
cert_status = CertificateStatuses.downloadable
title = _('Your certificate is available')
msg = _("You've earned a certificate for this course.")
if certs_api.has_html_certificates_enabled(course_key, course):
if certs_api.get_active_web_certificate(course) is not None:
cert_web_view_url = certs_api.get_certificate_url(
course_id=course_key, uuid=cert_downloadable_status['uuid']
)
return CertData(
cert_status,
title,
msg,
download_url=None,
cert_web_view_url=cert_web_view_url
)
else:
return CertData(
CertificateStatuses.generating, CertificateStatuses.generating,
_("We're working on it..."), _("We're working on it..."),
_( _(
...@@ -980,26 +972,34 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): ...@@ -980,26 +972,34 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
cert_web_view_url=None cert_web_view_url=None
) )
if cert_downloadable_status['is_downloadable']:
if certs_api.has_html_certificates_enabled(course_key, course):
if certs_api.get_active_web_certificate(course) is not None:
return CertData( return CertData(
cert_status, CertificateStatuses.downloadable,
title, _('Your certificate is available'),
msg, _("You've earned a certificate for this course."),
download_url=cert_downloadable_status['download_url'], download_url=None,
cert_web_view_url=None cert_web_view_url=certs_api.get_certificate_url(
course_id=course_key, uuid=cert_downloadable_status['uuid']
)
) )
else:
# If there is an error, the user should see the generating certificate message
# until a new certificate is generated.
return generating_certificate_message
if cert_downloadable_status['is_generating']:
return CertData( return CertData(
CertificateStatuses.generating, CertificateStatuses.downloadable,
_("We're working on it..."), _('Your certificate is available'),
_( _("You've earned a certificate for this course."),
"We're creating your certificate. You can keep working in your courses and a link to " download_url=cert_downloadable_status['download_url'],
"it will appear here and on your Dashboard when it is ready."
),
download_url=None,
cert_web_view_url=None cert_web_view_url=None
) )
if cert_downloadable_status['is_generating']:
return generating_certificate_message
# If the learner is in verified modes and the student did not have # If the learner is in verified modes and the student did not have
# their ID verified, we need to show message to ask learner to verify their ID first # their ID verified, we need to show message to ask learner to verify their ID first
missing_required_verification = ( missing_required_verification = (
......
...@@ -56,10 +56,9 @@ from django.utils.http import urlquote_plus ...@@ -56,10 +56,9 @@ from django.utils.http import urlquote_plus
${_("Course Progress for Student '{username}' ({email})").format(username=student.username, email=student.email)} ${_("Course Progress for Student '{username}' ({email})").format(username=student.username, email=student.email)}
</h2> </h2>
%if certificate_data:
<div class="wrapper-msg wrapper-auto-cert"> <div class="wrapper-msg wrapper-auto-cert">
<div id="errors-info" class="errors-info"></div> <div id="errors-info" class="errors-info"></div>
%if passed: %if certificate_data:
<div class="auto-cert-message" id="course-success"> <div class="auto-cert-message" id="course-success">
<div class="has-actions"> <div class="has-actions">
<% post_url = reverse('generate_user_cert', args=[unicode(course.id)]) %> <% post_url = reverse('generate_user_cert', args=[unicode(course.id)]) %>
...@@ -80,7 +79,6 @@ from django.utils.http import urlquote_plus ...@@ -80,7 +79,6 @@ from django.utils.http import urlquote_plus
</div> </div>
%endif %endif
</div> </div>
%endif
%if not course.disable_progress_graph: %if not course.disable_progress_graph:
<div class="grade-detail-graph" id="grade-detail-graph"></div> <div class="grade-detail-graph" id="grade-detail-graph"></div>
......
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