diff --git a/common/djangoapps/student/tests/tests.py b/common/djangoapps/student/tests/tests.py index 1a8c105c01..c28a54afe8 100644 --- a/common/djangoapps/student/tests/tests.py +++ b/common/djangoapps/student/tests/tests.py @@ -12,10 +12,11 @@ import pytz from django.conf import settings from django.test import TestCase from django.test.utils import override_settings -from django.test.client import RequestFactory +from django.test.client import RequestFactory, Client from django.contrib.auth.models import User, AnonymousUser -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, NoReverseMatch from django.http import HttpResponse +from unittest.case import SkipTest from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -146,12 +147,58 @@ class DashboardTest(TestCase): def setUp(self): self.course = CourseFactory.create(org=self.COURSE_ORG, display_name=self.COURSE_NAME, number=self.COURSE_SLUG) self.assertIsNotNone(self.course) - self.user = UserFactory.create(username="jack", email="jack@fake.edx.org") + self.user = UserFactory.create(username="jack", email="jack@fake.edx.org", password='test') CourseModeFactory.create( course_id=self.course.id, mode_slug='honor', mode_display_name='Honor Code', ) + self.client = Client() + + def check_verification_status_on(self, mode, value): + """ + Check that the css class and the status message are in the dashboard html. + """ + CourseEnrollment.enroll(self.user, self.course.location.course_id, mode=mode) + try: + response = self.client.get(reverse('dashboard')) + except NoReverseMatch: + raise SkipTest("Skip this test if url cannot be found (ie running from CMS tests)") + self.assertContains(response, "class=\"course {0}\"".format(mode)) + self.assertContains(response, value) + + @patch.dict("django.conf.settings.FEATURES", {'ENABLE_VERIFIED_CERTIFICATES': True}) + def test_verification_status_visible(self): + """ + Test that the certificate verification status for courses is visible on the dashboard. + """ + self.client.login(username="jack", password="test") + self.check_verification_status_on('verified', 'You\'re enrolled as a verified student') + self.check_verification_status_on('honor', 'You\'re enrolled as an honor code student') + self.check_verification_status_on('audit', 'You\'re auditing this course') + + def check_verification_status_off(self, mode, value): + """ + Check that the css class and the status message are not in the dashboard html. + """ + CourseEnrollment.enroll(self.user, self.course.location.course_id, mode=mode) + try: + response = self.client.get(reverse('dashboard')) + except NoReverseMatch: + raise SkipTest("Skip this test if url cannot be found (ie running from CMS tests)") + self.assertNotContains(response, "class=\"course {0}\"".format(mode)) + self.assertNotContains(response, value) + + @patch.dict("django.conf.settings.FEATURES", {'ENABLE_VERIFIED_CERTIFICATES': False}) + def test_verification_status_invisible(self): + """ + Test that the certificate verification status for courses is not visible on the dashboard + if the verified certificates setting is off. + """ + self.client.login(username="jack", password="test") + self.check_verification_status_off('verified', 'You\'re enrolled as a verified student') + self.check_verification_status_off('honor', 'You\'re enrolled as an honor code student') + self.check_verification_status_off('audit', 'You\'re auditing this course') def test_course_mode_info(self): verified_mode = CourseModeFactory.create( diff --git a/lms/djangoapps/courseware/features/certificates.py b/lms/djangoapps/courseware/features/certificates.py index 91e4f394c5..06d77e8008 100644 --- a/lms/djangoapps/courseware/features/certificates.py +++ b/lms/djangoapps/courseware/features/certificates.py @@ -6,6 +6,7 @@ from lettuce.django import django_url from course_modes.models import CourseMode from nose.tools import assert_equal + UPSELL_LINK_CSS = '.message-upsell a.action-upgrade[href*="edx/999/Certificates"]' def create_cert_course(): diff --git a/lms/envs/common.py b/lms/envs/common.py index c61db979d4..6287bfb5aa 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -172,6 +172,9 @@ FEATURES = { # Enable instructor dash beta version link 'ENABLE_INSTRUCTOR_BETA_DASHBOARD': True, + # Toggle to enable certificates of courses on dashboard + 'ENABLE_VERIFIED_CERTIFICATES': False, + # Allow use of the hint managment instructor view. 'ENABLE_HINTER_INSTRUCTOR_VIEW': False, diff --git a/lms/envs/test.py b/lms/envs/test.py index b20a23c470..edaa4c7c45 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -37,6 +37,8 @@ FEATURES['ENABLE_INSTRUCTOR_BETA_DASHBOARD'] = True FEATURES['ENABLE_SHOPPING_CART'] = True +FEATURES['ENABLE_VERIFIED_CERTIFICATES'] = True + # Enable this feature for course staff grade downloads, to enable acceptance tests FEATURES['ENABLE_S3_GRADE_DOWNLOADS'] = True FEATURES['ALLOW_COURSE_STAFF_GRADE_DOWNLOADS'] = True diff --git a/lms/static/sass/base/_variables.scss b/lms/static/sass/base/_variables.scss index cb96c3f92f..21998b995e 100644 --- a/lms/static/sass/base/_variables.scss +++ b/lms/static/sass/base/_variables.scss @@ -227,6 +227,15 @@ $verified-color-lvl3: $m-green-l2; $verified-color-lvl4: $m-green-l3; $verified-color-lvl5: $m-green-l4; +// STATE: honor code +$honorcode-color-lvl1: rgb(50, 165, 217); +$honorcode-color-lvl2: tint($honorcode-color-lvl1, 33%); + +// STATE: audit +$audit-color-lvl1: $light-gray; +$audit-color-lvl2: tint($audit-color-lvl1, 33%); + + // ==================== // ACTIONS: general @@ -307,6 +316,7 @@ $dashboard-profile-header-image: linear-gradient(-90deg, rgb(255,255,255), rgb(2 $dashboard-profile-header-color: transparent; $dashboard-profile-color: rgb(252,252,252); $dot-color: $light-gray; +$dashboard-course-cover-border: $light-gray; // MISC: course assets $content-wrapper-bg: $white; @@ -380,4 +390,3 @@ $f-monospace: 'Bitstream Vera Sans Mono', Consolas, Courier, monospace; // SPLINT: colors $msg-bg: $action-primary-bg; - diff --git a/lms/static/sass/elements/_typography.scss b/lms/static/sass/elements/_typography.scss index 2d677700c6..8170ca4b88 100644 --- a/lms/static/sass/elements/_typography.scss +++ b/lms/static/sass/elements/_typography.scss @@ -277,7 +277,7 @@ } %copy-badge { - @extend %t-title8; + @extend %t-title9; @extend %t-weight3; border-radius: ($baseline/5); padding: ($baseline/2) $baseline; diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss index 8c987c9630..6991fba25b 100644 --- a/lms/static/sass/multicourse/_dashboard.scss +++ b/lms/static/sass/multicourse/_dashboard.scss @@ -374,15 +374,19 @@ .cover { @include box-sizing(border-box); + @include transition(all 0.15s linear 0s); + overflow: hidden; + position: relative; float: left; height: 100%; max-height: 100%; - margin: 0px; - overflow: hidden; - position: relative; - @include transition(all 0.15s linear 0s); width: 200px; height: 120px; + margin: 0px; + border-radius: ($baseline/10); + border: 1px solid $dashboard-course-cover-border; + border-bottom: 4px solid $dashboard-course-cover-border; + padding: ($baseline/10); img { width: 100%; @@ -491,28 +495,43 @@ } } + // "enrolled as" status + .sts-enrollment { + position: absolute; + top: 105px; + left: 0; + display: inline-block; + text-align: center; + width: 200px; + + .label { + @extend %text-sr; + } + + .sts-enrollment-value { + @extend %ui-depth1; + @extend %copy-badge; + border-radius: 0; + padding: ($baseline/4) ($baseline/2) ($baseline/4) ($baseline/2); + } + } + // ==================== - // STATE: course mode - verified + // CASE: "enrolled as" status - verified &.verified { - @extend %ui-depth2; - position: relative; + // changes to cover .cover { - border-radius: ($baseline/10); - border: 1px solid $verified-color-lvl3; - border-bottom: 4px solid $verified-color-lvl3; + border-color: $verified-color-lvl3; padding: ($baseline/10); } // course enrollment status message .sts-enrollment { - display: inline-block; position: absolute; - top: 105px; left: 55px; - bottom: ($baseline/2); - text-align: center; + width: auto; .label { @extend %text-sr; @@ -526,16 +545,46 @@ top: -10px; } + // status message .sts-enrollment-value { - @extend %ui-depth1; - @extend %copy-badge; - border-radius: 0; padding: ($baseline/4) ($baseline/2) ($baseline/4) $baseline; background: $verified-color-lvl3; - color: $white; + color: tint($verified-color-lvl1, 85%); } } } + + // CASE: "enrolled as" status - honor code + &.honor { + + // changes to cover + .cover { + border-color: $honorcode-color-lvl2; + padding: ($baseline/10); + } + + // status message + .sts-enrollment-value { + background: $honorcode-color-lvl1; + color: tint($honorcode-color-lvl1, 85%); + } + } + + // CASE: "enrolled as" status - auditing + &.audit { + + // changes to cover + .cover { + border-color: $audit-color-lvl2; + padding: ($baseline/10); + } + + // status message + .sts-enrollment-value { + background: $audit-color-lvl1; + color: shade($audit-color-lvl1, 33%); + } + } } // ==================== diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index f415830668..229fed81d4 100644 --- a/lms/templates/dashboard/_dashboard_course_listing.html +++ b/lms/templates/dashboard/_dashboard_course_listing.html @@ -11,7 +11,7 @@ cert_name_short = course.cert_name_short if cert_name_short == "": cert_name_short = settings.CERT_NAME_SHORT - + cert_name_long = course.cert_name_long if cert_name_long == "": cert_name_long = settings.CERT_NAME_LONG @@ -21,7 +21,11 @@ <%namespace name='static' file='../static_content.html'/>
  • -
    + % if settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES'): +
    + % else: +
    + %endif <% course_target = reverse('info', args=[course.id]) %> @@ -35,13 +39,24 @@ ${_('{course_number} {course_name} Cover Image').format(course_number=course.number, course_name=course.display_name_with_default) | h} % endif - - % if enrollment.mode == "verified": - - ${_("Enrolled as: ")} - ID Verified Ribbon/Badge - ${_("ID Verified")} - + % if settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES'): + % if enrollment.mode == "verified": + + ${_("Enrolled as: ")} + ID Verified Ribbon/Badge + ${_("Verified")} + + % elif enrollment.mode == "honor": + + ${_("Enrolled as: ")} + ${_("Honor Code")} + + % elif enrollment.mode == "audit": + + ${_("Enrolled as: ")} + ${_("Auditing")} + + % endif % endif