Merge pull request #15705 from edx/ssemenova/ed-526
EDUCATOR-526 Update view certificate button
This commit is contained in:
@@ -514,6 +514,7 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
expiration_datetime=datetime.now(pytz.UTC) - timedelta(days=1)
|
||||
)
|
||||
|
||||
self.course.certificate_available_date = datetime.now(pytz.UTC) - timedelta(days=1)
|
||||
CourseEnrollment.enroll(self.user, self.course.id, mode='honor')
|
||||
|
||||
self.course.start = datetime.now(pytz.UTC) - timedelta(days=2)
|
||||
|
||||
@@ -93,7 +93,12 @@ def course_start_date_is_default(start, advertised_start):
|
||||
return advertised_start is None and start == DEFAULT_START_DATE
|
||||
|
||||
|
||||
def may_certify_for_course(certificates_display_behavior, certificates_show_before_end, has_ended):
|
||||
def may_certify_for_course(
|
||||
certificates_display_behavior,
|
||||
certificates_show_before_end,
|
||||
has_ended,
|
||||
certificate_available_date
|
||||
):
|
||||
"""
|
||||
Returns whether it is acceptable to show the student a certificate download
|
||||
link for a course.
|
||||
@@ -105,12 +110,24 @@ def may_certify_for_course(certificates_display_behavior, certificates_show_befo
|
||||
certificates_show_before_end (bool): whether user can download the
|
||||
course's certificates before the course has ended.
|
||||
has_ended (bool): Whether the course has ended.
|
||||
certificate_available_date (datetime): the date the certificate is available on for the course.
|
||||
"""
|
||||
show_early = (
|
||||
certificates_display_behavior in ('early_with_info', 'early_no_info')
|
||||
or certificates_show_before_end
|
||||
)
|
||||
return show_early or has_ended
|
||||
past_availability_date = (
|
||||
certificate_available_date
|
||||
and certificate_available_date < datetime.now(utc)
|
||||
)
|
||||
|
||||
if show_early:
|
||||
return True
|
||||
if past_availability_date:
|
||||
return True
|
||||
if (certificate_available_date is None) and has_ended:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def sorting_score(start, advertised_start, announcement):
|
||||
|
||||
@@ -1065,7 +1065,8 @@ class CourseDescriptor(CourseFields, SequenceDescriptor, LicenseMixin):
|
||||
return course_metadata_utils.may_certify_for_course(
|
||||
self.certificates_display_behavior,
|
||||
self.certificates_show_before_end,
|
||||
self.has_ended()
|
||||
self.has_ended(),
|
||||
self.certificate_available_date
|
||||
)
|
||||
|
||||
def has_started(self):
|
||||
|
||||
@@ -161,11 +161,14 @@ class CourseMetadataUtilsTestCase(TestCase):
|
||||
TestScenario((DEFAULT_START_DATE, None), True),
|
||||
]),
|
||||
FunctionTest(may_certify_for_course, [
|
||||
TestScenario(('early_with_info', True, True), True),
|
||||
TestScenario(('early_no_info', False, False), True),
|
||||
TestScenario(('end', True, False), True),
|
||||
TestScenario(('end', False, True), True),
|
||||
TestScenario(('end', False, False), False),
|
||||
TestScenario(('early_with_info', True, True, test_datetime), True),
|
||||
TestScenario(('early_no_info', False, False, test_datetime), True),
|
||||
TestScenario(('end', True, False, test_datetime), True),
|
||||
TestScenario(('end', False, True, test_datetime), True),
|
||||
TestScenario(('end', False, False, _NEXT_WEEK), False),
|
||||
TestScenario(('end', False, False, _LAST_WEEK), True),
|
||||
TestScenario(('end', False, False, None), False),
|
||||
TestScenario(('early_with_info', False, False, None), True),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from contextlib import contextmanager
|
||||
from functools import wraps
|
||||
|
||||
import ddt
|
||||
from datetime import datetime
|
||||
from config_models.models import cache
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
@@ -92,7 +93,8 @@ class CertificateDownloadableStatusTests(WebCertificateTestMixin, ModuleStoreTes
|
||||
self.course = CourseFactory.create(
|
||||
org='edx',
|
||||
number='verified',
|
||||
display_name='Verified Course'
|
||||
display_name='Verified Course',
|
||||
end=datetime.now()
|
||||
)
|
||||
|
||||
self.request_factory = RequestFactory()
|
||||
|
||||
@@ -1216,6 +1216,8 @@ class ProgressPageBaseTests(ModuleStoreTestCase):
|
||||
self.course = CourseFactory.create(
|
||||
start=datetime(2013, 9, 16, 7, 17, 28),
|
||||
grade_cutoffs={u'çü†øƒƒ': 0.75, 'Pass': 0.5},
|
||||
end=datetime.now(),
|
||||
certificate_available_date=datetime.now(),
|
||||
**options
|
||||
)
|
||||
|
||||
@@ -2052,6 +2054,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
|
||||
self.course = CourseFactory.create(
|
||||
org='edx',
|
||||
number='verified',
|
||||
end=datetime.now(),
|
||||
display_name='Verified Course',
|
||||
grade_cutoffs={'cutoff': 0.75, 'Pass': 0.5}
|
||||
)
|
||||
|
||||
@@ -112,7 +112,9 @@ log = logging.getLogger("edx.courseware")
|
||||
# credit and verified modes.
|
||||
REQUIREMENTS_DISPLAY_MODES = CourseMode.CREDIT_MODES + [CourseMode.VERIFIED]
|
||||
|
||||
CertData = namedtuple("CertData", ["cert_status", "title", "msg", "download_url", "cert_web_view_url"])
|
||||
CertData = namedtuple(
|
||||
"CertData", ["cert_status", "title", "msg", "download_url", "cert_web_view_url", "may_view_certificate"]
|
||||
)
|
||||
|
||||
|
||||
def user_groups(user):
|
||||
@@ -919,6 +921,7 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
Returns:
|
||||
returns dict if course certificate is available else None.
|
||||
"""
|
||||
from lms.djangoapps.courseware.courses import get_course_by_id
|
||||
|
||||
if enrollment_mode == CourseMode.AUDIT:
|
||||
return CertData(
|
||||
@@ -926,24 +929,28 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
_('Your enrollment: Audit track'),
|
||||
_('You are enrolled in the audit track for this course. The audit track does not include a certificate.'),
|
||||
download_url=None,
|
||||
cert_web_view_url=None
|
||||
cert_web_view_url=None,
|
||||
may_view_certificate=None
|
||||
)
|
||||
|
||||
show_generate_cert_btn = (
|
||||
show_message = (
|
||||
is_active and CourseMode.is_eligible_for_certificate(enrollment_mode)
|
||||
and certs_api.cert_generation_enabled(course_key)
|
||||
)
|
||||
|
||||
if not show_generate_cert_btn:
|
||||
if not show_message:
|
||||
return None
|
||||
|
||||
may_view_certificate = course_key and get_course_by_id(course_key).may_certify()
|
||||
|
||||
if certs_api.is_certificate_invalid(student, course_key):
|
||||
return CertData(
|
||||
CertificateStatuses.invalidated,
|
||||
_('Your certificate has been invalidated'),
|
||||
_('Please contact your course team if you have any questions.'),
|
||||
download_url=None,
|
||||
cert_web_view_url=None
|
||||
cert_web_view_url=None,
|
||||
may_view_certificate=None
|
||||
)
|
||||
|
||||
cert_downloadable_status = certs_api.certificate_downloadable_status(student, course_key)
|
||||
@@ -957,7 +964,12 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
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)
|
||||
return CertData(cert_status,
|
||||
title,
|
||||
msg,
|
||||
download_url=None,
|
||||
cert_web_view_url=cert_web_view_url,
|
||||
may_view_certificate=may_view_certificate)
|
||||
else:
|
||||
return CertData(
|
||||
CertificateStatuses.generating,
|
||||
@@ -967,11 +979,17 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
"to 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,
|
||||
may_view_certificate=None
|
||||
)
|
||||
|
||||
return CertData(
|
||||
cert_status, title, msg, download_url=cert_downloadable_status['download_url'], cert_web_view_url=None
|
||||
cert_status,
|
||||
title,
|
||||
msg,
|
||||
download_url=cert_downloadable_status['download_url'],
|
||||
cert_web_view_url=None,
|
||||
may_view_certificate=may_view_certificate
|
||||
)
|
||||
|
||||
if cert_downloadable_status['is_generating']:
|
||||
@@ -983,7 +1001,8 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
"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,
|
||||
may_view_certificate=None
|
||||
)
|
||||
|
||||
# If the learner is in verified modes and the student did not have
|
||||
@@ -1001,7 +1020,8 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
'verified identity.'
|
||||
).format(platform_name=platform_name),
|
||||
download_url=None,
|
||||
cert_web_view_url=None
|
||||
cert_web_view_url=None,
|
||||
may_view_certificate=None
|
||||
)
|
||||
|
||||
return CertData(
|
||||
@@ -1009,7 +1029,8 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode):
|
||||
_('Congratulations, you qualified for a certificate!'),
|
||||
_('You can keep working for a higher grade, or request your certificate now.'),
|
||||
download_url=None,
|
||||
cert_web_view_url=None
|
||||
cert_web_view_url=None,
|
||||
may_view_certificate=may_view_certificate
|
||||
)
|
||||
|
||||
|
||||
@@ -1355,7 +1376,7 @@ def _track_successful_certificate_generation(user_id, course_id): # pylint: dis
|
||||
Track a successful certificate generation event.
|
||||
|
||||
Arguments:
|
||||
user_id (str): The ID of the user generting the certificate.
|
||||
user_id (str): The ID of the user generating the certificate.
|
||||
course_id (CourseKey): Identifier for the course.
|
||||
Returns:
|
||||
None
|
||||
|
||||
@@ -13,6 +13,7 @@ Test utilities for mobile API tests:
|
||||
from datetime import timedelta
|
||||
|
||||
import ddt
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils import timezone
|
||||
@@ -39,7 +40,10 @@ class MobileAPITestCase(ModuleStoreTestCase, APITestCase):
|
||||
"""
|
||||
def setUp(self):
|
||||
super(MobileAPITestCase, self).setUp()
|
||||
self.course = CourseFactory.create(mobile_available=True, static_asset_path="needed_for_split")
|
||||
self.course = CourseFactory.create(
|
||||
mobile_available=True,
|
||||
static_asset_path="needed_for_split",
|
||||
end=datetime.datetime.now())
|
||||
self.user = UserFactory.create()
|
||||
self.password = 'test'
|
||||
self.username = self.user.username
|
||||
|
||||
@@ -67,6 +67,7 @@ from django.utils.http import urlquote_plus
|
||||
<h4 class="hd hd-4 title">${certificate_data.title}</h4>
|
||||
<p class="copy">${certificate_data.msg}</p>
|
||||
</div>
|
||||
%if certificate_data.may_view_certificate:
|
||||
<div class="msg-actions">
|
||||
%if certificate_data.cert_web_view_url:
|
||||
<a class="btn" href="${certificate_data.cert_web_view_url}" target="_blank">${_("View Certificate")} <span class="sr">${_("Opens in a new browser window")}</span></a>
|
||||
@@ -76,6 +77,7 @@ from django.utils.http import urlquote_plus
|
||||
<button class="btn generate_certs" data-endpoint="${post_url}" id="btn_generate_cert">${_('Request Certificate')}</button>
|
||||
%endif
|
||||
</div>
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('course_overviews', '0013_courseoverview_language'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='courseoverview',
|
||||
name='certificate_available_date',
|
||||
field=models.DateTimeField(default=None, null=True),
|
||||
),
|
||||
]
|
||||
@@ -75,6 +75,7 @@ class CourseOverview(TimeStampedModel):
|
||||
has_any_active_web_certificate = BooleanField(default=False)
|
||||
cert_name_short = TextField()
|
||||
cert_name_long = TextField()
|
||||
certificate_available_date = DateTimeField(default=None, null=True)
|
||||
|
||||
# Grading
|
||||
lowest_passing_grade = DecimalField(max_digits=5, decimal_places=2, null=True)
|
||||
@@ -172,6 +173,7 @@ class CourseOverview(TimeStampedModel):
|
||||
course_overview.has_any_active_web_certificate = (get_active_web_certificate(course) is not None)
|
||||
course_overview.cert_name_short = course.cert_name_short
|
||||
course_overview.cert_name_long = course.cert_name_long
|
||||
course_overview.certificate_available_date = course.certificate_available_date
|
||||
course_overview.lowest_passing_grade = lowest_passing_grade
|
||||
course_overview.end_of_course_survey_url = course.end_of_course_survey_url
|
||||
|
||||
@@ -476,7 +478,8 @@ class CourseOverview(TimeStampedModel):
|
||||
return course_metadata_utils.may_certify_for_course(
|
||||
self.certificates_display_behavior,
|
||||
self.certificates_show_before_end,
|
||||
self.has_ended()
|
||||
self.has_ended(),
|
||||
self.certificate_available_date
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user