diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index 3f956d2a7c65d4a999bfb05b2c5caaa6762ff6ef..dec14876041f25856781157241ef9ba452a4164b 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -12,39 +12,39 @@ from datetime import datetime, timedelta import ddt import six from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing +from course_modes.models import CourseMode from django.conf import settings -from django.test import RequestFactory, TestCase +from django.test import TestCase from django.test.utils import override_settings from django.urls import reverse from django.utils.timezone import now +from entitlements.tests.factories import CourseEntitlementFactory from milestones.tests.utils import MilestonesTestCaseMixin from mock import patch from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from pyquery import PyQuery as pq from six.moves import range +from student.helpers import DISABLE_UNENROLL_CERT_STATES +from student.models import CourseEnrollment, UserProfile +from student.signals import REFUND_ORDER +from student.tests.factories import CourseEnrollmentFactory, UserFactory +from util.milestones_helpers import get_course_milestones, remove_prerequisite_course, set_prerequisite_courses +from util.testing import UrlResetMixin +from xmodule.modulestore import ModuleStoreEnum +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory -from course_modes.models import CourseMode -from entitlements.tests.factories import CourseEntitlementFactory +from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory from openedx.core.djangoapps.catalog.tests.factories import ProgramFactory from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory from openedx.core.djangoapps.schedules.config import COURSE_UPDATE_WAFFLE_FLAG from openedx.core.djangoapps.schedules.tests.factories import ScheduleFactory from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context -from openedx.core.djangoapps.user_authn.cookies import _get_user_info_cookie_data from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from openedx.features.course_experience.tests.views.helpers import add_course_mode -from student.helpers import DISABLE_UNENROLL_CERT_STATES -from student.models import CourseEnrollment, UserProfile -from student.signals import REFUND_ORDER -from student.tests.factories import CourseEnrollmentFactory, UserFactory -from util.milestones_helpers import get_course_milestones, remove_prerequisite_course, set_prerequisite_courses -from util.testing import UrlResetMixin -from xmodule.modulestore import ModuleStoreEnum -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory PASSWORD = 'test' @@ -222,6 +222,33 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, response = self.client.get(self.path) self.assertRedirects(response, reverse('account_settings')) + def test_grade_doesnt_appears_before_course_end_date(self): + """ + Verify that learners are not able to see their final grade before the end + of course in the learner dashboard + """ + self.course = CourseFactory.create(end=self.TOMORROW, emit_signals=True) + self.course_enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user) + GeneratedCertificateFactory(status='notpassing', course_id=self.course.id, user=self.user, grade=0.45) + + response = self.client.get(reverse('dashboard')) + # The final grade does not appear before the course has ended + self.assertNotContains(response, 'Your final grade:') + self.assertNotContains(response, '<span class="grade-value">45%</span>') + + def test_grade_appears_after_course_has_ended(self): + """ + Verify that learners are able to see their final grade of the course in + the learner dashboard after the course had ended + """ + self.course = CourseFactory.create(end=self.THREE_YEARS_AGO, emit_signals=True) + self.course_enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user) + GeneratedCertificateFactory(status='notpassing', course_id=self.course.id, user=self.user, grade=0.45) + + response = self.client.get(reverse('dashboard')) + self.assertContains(response, 'Your final grade:') + self.assertContains(response, '<span class="grade-value">45%</span>') + @patch.multiple('django.conf.settings', **MOCK_SETTINGS) @ddt.data( *itertools.product( diff --git a/common/djangoapps/util/course.py b/common/djangoapps/util/course.py index 1ef703d4243e52a2256987fb4e7e0ede413e4523..1c738746fb3e114228ec37c09bb4000e6df6420d 100644 --- a/common/djangoapps/util/course.py +++ b/common/djangoapps/util/course.py @@ -10,6 +10,7 @@ import six.moves.urllib.error import six.moves.urllib.parse import six.moves.urllib.request from django.conf import settings +from django.utils.timezone import now from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -73,3 +74,9 @@ def has_certificates_enabled(course): if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False): return False return course.cert_html_view_enabled + + +def should_display_grade(end_date): + if end_date and end_date < now().replace(hour=0, minute=0, second=0, microsecond=0): + return True + return False diff --git a/lms/templates/dashboard/_dashboard_certificate_information.html b/lms/templates/dashboard/_dashboard_certificate_information.html index 651f80cd9eebd9620003b946d64de726a122f23b..1d8d29cc8814b44345df2bb73da44863f4acb345 100644 --- a/lms/templates/dashboard/_dashboard_certificate_information.html +++ b/lms/templates/dashboard/_dashboard_certificate_information.html @@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _ from openedx.core.djangolib.markup import HTML, Text from course_modes.models import CourseMode +from util.course import should_display_grade %> <%namespace name='static' file='../static_content.html'/> @@ -44,9 +45,11 @@ else: </div> % else: <div class="message message-status ${status_css_class} is-shown"> - <p class="message-copy">${_("Your final grade:")} - <span class="grade-value">${"{0:.0f}%".format(float(cert_status['grade'])*100)}</span>. - + <p class="message-copy"> + % if should_display_grade(course_overview.end): + ${_("Your final grade:")} + <span class="grade-value">${"{0:.0f}%".format(float(cert_status['grade'])*100)}</span>. + % endif % if cert_status['status'] == 'notpassing': % if enrollment.mode != 'audit': ${_("Grade required for a {cert_name_short}:").format(cert_name_short=cert_name_short)}