diff --git a/common/djangoapps/student/tests/test_activate_account.py b/common/djangoapps/student/tests/test_activate_account.py index e32f6c78b4e3b5bbe6455ae081b3f2c0b22eab5c..30cd2e1a7a1511ab0b37b8f404cf8a8124b67228 100644 --- a/common/djangoapps/student/tests/test_activate_account.py +++ b/common/djangoapps/student/tests/test_activate_account.py @@ -112,6 +112,7 @@ class TestActivateAccount(TestCase): def test_activation_without_keys(self, mock_segment_identify): self.assert_no_tracking(mock_segment_identify) + @override_settings(FEATURES=dict(settings.FEATURES, DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR=True)) def test_account_activation_message(self): """ Verify that account correct activation message is displayed. @@ -121,29 +122,59 @@ class TestActivateAccount(TestCase): """ # Log in with test user. self.login() - expected_message = ( - u"Check your {email_start}{email}{email_end} inbox for an account activation link from " - u"{platform_name}. If you need help, contact {link_start}{platform_name} Support{link_end}." - ).format( - platform_name=self.platform_name, - email_start="<strong>", - email_end="</strong>", - email=self.user.email, - link_start="<a target='_blank' href='{activation_email_support_link}'>".format( - activation_email_support_link=self.activation_email_support_link, - ), - link_end="</a>", + expected_message = render_to_string( + 'registration/account_activation_sidebar_notice.html', + { + 'email': self.user.email, + 'platform_name': self.platform_name, + 'activation_email_support_link': self.activation_email_support_link + } + ) + + response = self.client.get(reverse('dashboard')) + self.assertContains(response, expected_message, html=True) + + # Now make sure account activation message goes away when user activated the account + self.user.is_active = True + self.user.save() + self.login() + expected_message = render_to_string( + 'registration/account_activation_sidebar_notice.html', + { + 'email': self.user.email, + 'platform_name': self.platform_name, + 'activation_email_support_link': self.activation_email_support_link + } + ) + response = self.client.get(reverse('dashboard')) + self.assertNotContains(response, expected_message, html=True) + + @override_settings(FEATURES=dict(settings.FEATURES, DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR=False)) + def test_account_activation_message_disabled(self): + """ + Verify that old account activation message is displayed when + DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR is disabled. + """ + # Log in with test user. + self.login() + expected_message = render_to_string( + 'registration/activate_account_notice.html', + {'email': self.user.email} ) response = self.client.get(reverse('dashboard')) - self.assertContains(response, expected_message) + self.assertContains(response, expected_message, html=True) # Now make sure account activation message goes away when user activated the account self.user.is_active = True self.user.save() self.login() + expected_message = render_to_string( + 'registration/activate_account_notice.html', + {'email': self.user.email} + ) response = self.client.get(reverse('dashboard')) - self.assertNotContains(response, expected_message) + self.assertNotContains(response, expected_message, html=True) def test_account_activation_notification_on_logistration(self): """ diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index 6a47a230d9bab2a45af2628f5fb03e8ee9f46ced..e3f85cb4e71f09574fa54f46d47e9a58d0b8769d 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -27,7 +27,6 @@ from milestones.tests.utils import MilestonesTestCaseMixin 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.site_configuration.tests.test_util import with_site_configuration_context from pyquery import PyQuery as pq from student.cookies import get_user_info_cookie_data from student.helpers import DISABLE_UNENROLL_CERT_STATES @@ -265,11 +264,6 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, 'DASHBOARD_TWITTER': True, }, } - MOCK_SETTINGS_HIDE_COURSES = { - 'FEATURES': { - 'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED': True, - } - } def setUp(self): """ @@ -625,40 +619,6 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, response = self.client.get(self.path) self.assertEqual(pq(response.content)(self.EMAIL_SETTINGS_ELEMENT_ID).length, 0) - @patch.multiple('django.conf.settings', **MOCK_SETTINGS_HIDE_COURSES) - def test_hide_dashboard_courses_until_activated(self): - """ - Verify that when the HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED feature is enabled, - inactive users don't see the Courses list, but active users still do. - """ - # Ensure active users see the course list - self.assertTrue(self.user.is_active) - response = self.client.get(reverse('dashboard')) - self.assertIn('You are not enrolled in any courses yet.', response.content) - - # Ensure inactive users don't see the course list - self.user.is_active = False - self.user.save() - response = self.client.get(reverse('dashboard')) - self.assertNotIn('You are not enrolled in any courses yet.', response.content) - - def test_show_empty_dashboard_message(self): - """ - Verify that when the EMPTY_DASHBOARD_MESSAGE feature is set, - its text is displayed in an empty courses list. - """ - empty_dashboard_message = "Check out our lovely <i>free</i> courses!" - response = self.client.get(reverse('dashboard')) - self.assertIn('You are not enrolled in any courses yet.', response.content) - self.assertNotIn(empty_dashboard_message, response.content) - - with with_site_configuration_context(configuration={ - "EMPTY_DASHBOARD_MESSAGE": empty_dashboard_message, - }): - response = self.client.get(reverse('dashboard')) - self.assertIn('You are not enrolled in any courses yet.', response.content) - self.assertIn(empty_dashboard_message, response.content) - @staticmethod def _remove_whitespace_from_html_string(html): return ''.join(html.split()) diff --git a/common/djangoapps/student/views/dashboard.py b/common/djangoapps/student/views/dashboard.py index cc7d42ef0b8e3b4c39eed1af4dbde05a1a362214..78e2b4bd2c609df6d33a6ff6ae3a69417753522d 100644 --- a/common/djangoapps/student/views/dashboard.py +++ b/common/djangoapps/student/views/dashboard.py @@ -40,7 +40,6 @@ from openedx.core.djangoapps.programs.utils import ProgramDataExtender, ProgramP from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.util.maintenance_banner import add_maintenance_banner from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace -from openedx.core.djangolib.markup import HTML, Text from openedx.features.enterprise_support.api import get_dashboard_consent_notification from shoppingcart.api import order_history from shoppingcart.models import CourseRegistrationCode, DonationConfiguration @@ -563,13 +562,6 @@ def student_dashboard(request): activation_email_support_link = configuration_helpers.get_value( 'ACTIVATION_EMAIL_SUPPORT_LINK', settings.ACTIVATION_EMAIL_SUPPORT_LINK ) or settings.SUPPORT_SITE_LINK - hide_dashboard_courses_until_activated = configuration_helpers.get_value( - 'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', - settings.FEATURES.get('HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', False) - ) - empty_dashboard_message = configuration_helpers.get_value( - 'EMPTY_DASHBOARD_MESSAGE', None - ) # Get the org whitelist or the org blacklist for the current site site_org_whitelist, site_org_blacklist = get_org_black_and_whitelist_for_site() @@ -610,21 +602,28 @@ def student_dashboard(request): ) course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True) - # Display activation message - activate_account_message = '' - if not user.is_active: - activate_account_message = Text(_( - "Check your {email_start}{email}{email_end} inbox for an account activation link from {platform_name}. " - "If you need help, contact {link_start}{platform_name} Support{link_end}." - )).format( - platform_name=platform_name, - email_start=HTML("<strong>"), - email_end=HTML("</strong>"), - email=user.email, - link_start=HTML("<a target='_blank' href='{activation_email_support_link}'>").format( - activation_email_support_link=activation_email_support_link, - ), - link_end=HTML("</a>"), + sidebar_account_activation_message = '' + banner_account_activation_message = '' + display_account_activation_message_on_sidebar = configuration_helpers.get_value( + 'DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR', + settings.FEATURES.get('DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR', False) + ) + + # Display activation message in sidebar if DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR + # flag is active. Otherwise display existing message at the top. + if display_account_activation_message_on_sidebar and not user.is_active: + sidebar_account_activation_message = render_to_string( + 'registration/account_activation_sidebar_notice.html', + { + 'email': user.email, + 'platform_name': platform_name, + 'activation_email_support_link': activation_email_support_link + } + ) + elif not user.is_active: + banner_account_activation_message = render_to_string( + 'registration/activate_account_notice.html', + {'email': user.email} ) enterprise_message = get_dashboard_consent_notification(request, user, course_enrollments) @@ -790,12 +789,13 @@ def student_dashboard(request): 'enrollment_message': enrollment_message, 'redirect_message': redirect_message, 'account_activation_messages': account_activation_messages, - 'activate_account_message': activate_account_message, 'course_enrollments': course_enrollments, 'course_entitlements': course_entitlements, 'course_entitlement_available_sessions': course_entitlement_available_sessions, 'unfulfilled_entitlement_pseudo_sessions': unfulfilled_entitlement_pseudo_sessions, 'course_optouts': course_optouts, + 'banner_account_activation_message': banner_account_activation_message, + 'sidebar_account_activation_message': sidebar_account_activation_message, 'staff_access': staff_access, 'errored_courses': errored_courses, 'show_courseware_links_for': show_courseware_links_for, @@ -825,9 +825,6 @@ def student_dashboard(request): 'disable_courseware_js': True, 'display_course_modes_on_dashboard': enable_verified_certificates and display_course_modes_on_dashboard, 'display_sidebar_on_dashboard': display_sidebar_on_dashboard, - 'display_sidebar_account_activation_message': not(user.is_active or hide_dashboard_courses_until_activated), - 'display_dashboard_courses': (user.is_active or not hide_dashboard_courses_until_activated), - 'empty_dashboard_message': empty_dashboard_message, } if ecommerce_service.is_enabled(request.user): diff --git a/lms/envs/common.py b/lms/envs/common.py index 7dd42d762c5d4b22a5f46394ff8a0f88c59e93aa..2725704eccb70eb7c0c6ddd2d42bbb461cfb8284 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -133,9 +133,6 @@ FEATURES = { # Can be turned off if course lists need to be hidden. Effects views and templates. 'COURSES_ARE_BROWSABLE': True, - # Set to hide the courses list on the Learner Dashboard if they are not enrolled in any courses yet. - 'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED': False, - # Enables ability to restrict enrollment in specific courses by the user account login method 'RESTRICT_ENROLL_BY_REG_METHOD': False, @@ -378,6 +375,9 @@ FEATURES = { # See LEARNER-493 'ENABLE_ONE_CLICK_PROGRAM_PURCHASE': False, + # Whether to display account activation notification on dashboard. + 'DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR': False, + # Allow users to change their email address. 'ALLOW_EMAIL_ADDRESS_CHANGE': True, diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss index 7de3d8b8abb20c20c55d56aed9fee06841f25fdf..63b756219561db8e3595f6982862c20fa41089b4 100644 --- a/lms/static/sass/multicourse/_dashboard.scss +++ b/lms/static/sass/multicourse/_dashboard.scss @@ -1098,7 +1098,7 @@ .empty-dashboard-message { border: 3px solid $gray-l4; background: $gray-l6; - padding: ($baseline*2) ($baseline/10); + padding: ($baseline*2) 0; text-align: center; p { @@ -1109,12 +1109,7 @@ text-shadow: 0 1px rgba(255,255,255, 0.6); } - p.custom-message { - @include font-size(14); - text-shadow: none; - } - - a.btn { + a { background-color: theme-color('primary'); border: 1px solid theme-color('primary'); box-shadow: 0 1px 8px 0 $shadow-l1; diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index 5369c2e9f27a2f380e02be2a16c1e15d29dc6555..3be671e7ec99c2c21635688b28f971ea2f5a87a1 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -122,11 +122,10 @@ from student.models import CourseEnrollment <main id="main" aria-label="Content" tabindex="-1"> <div class="dashboard" id="dashboard-main"> + <div class="main-container"> <div class="my-courses" id="my-courses"> - % if display_dashboard_courses: <%include file="learner_dashboard/_dashboard_navigation_courses.html"/> - % endif % if len(course_entitlements + course_enrollments) > 0: <ul class="listing-courses"> @@ -196,20 +195,14 @@ from student.models import CourseEnrollment </ul> % else: <div class="empty-dashboard-message"> - % if display_dashboard_courses: - <p>${_("You are not enrolled in any courses yet.")}</p> - % if empty_dashboard_message: - <p class="custom-message">${empty_dashboard_message | n, decode.utf8}</p> - %endif - % if settings.FEATURES.get('COURSES_ARE_BROWSABLE'): - <a class="btn btn-primary" href="${marketing_link('COURSES')}"> - ${_("Explore courses")} - </a> - %endif - % else: - <p>${_("Activate your account!")}</p> - <p class="custom-message">${ activate_account_message | n, decode.utf8 }</p> - % endif + <p>${_("You are not enrolled in any courses yet.")}</p> + + % if settings.FEATURES.get('COURSES_ARE_BROWSABLE'): + <a class="btn btn-primary" href="${marketing_link('COURSES')}"> + ${_("Explore courses")} + </a> + + %endif </div> % endif @@ -232,9 +225,9 @@ from student.models import CourseEnrollment </div> </div> <div class="side-container"> - %if display_sidebar_account_activation_message: + %if sidebar_account_activation_message: <div class="sidebar-notification"> - <%include file="${static.get_template_path('registration/account_activation_sidebar_notice.html')}" /> + ${sidebar_account_activation_message | n, decode.utf8} </div> %endif diff --git a/lms/templates/registration/account_activation_sidebar_notice.html b/lms/templates/registration/account_activation_sidebar_notice.html index be474707d23202314521006bcd63e91fbbed3dab..5fc1a8ca75da13d831c9c9bc72441cd678c1fc6e 100644 --- a/lms/templates/registration/account_activation_sidebar_notice.html +++ b/lms/templates/registration/account_activation_sidebar_notice.html @@ -15,7 +15,20 @@ from openedx.core.djangolib.markup import HTML, Text <span class="sr">Notice</span> ${_("Activate your account!")} </span> - <p class="status-note">${ activate_account_message | n, decode.utf8 }</p> + <p class="status-note">${Text(_( + "Check your {email_start}{email}{email_end} inbox for an account activation link from {platform_name}. " + "If you need help, contact {link_start}{platform_name} Support{link_end}." + )).format( + platform_name=platform_name, + email_start=HTML("<strong>"), + email_end=HTML("</strong>"), + email=email, + link_start=HTML("<a target='_blank' href='{activation_email_support_link}'>").format( + activation_email_support_link=activation_email_support_link, + ), + link_end=HTML("</a>"), + )} + </p> ## TODO: Add resend activation email functionality. ## TODO: Implementation of this is part of ENT-353. ## <button class="btn btn-neutral"><i class="fa fa-envelope-o"></i> Resend Activation Email </button> diff --git a/lms/templates/registration/activate_account_notice.html b/lms/templates/registration/activate_account_notice.html new file mode 100644 index 0000000000000000000000000000000000000000..80b809943ebe2f1bafe4ae990d5386b0abfbcdc5 --- /dev/null +++ b/lms/templates/registration/activate_account_notice.html @@ -0,0 +1,28 @@ +<%page expression_filter="h"/> +<%! +from django.utils.translation import ugettext as _ +from openedx.core.djangolib.markup import HTML, Text +%> +<div class="wrapper-msg urgency-high"> + <div class="msg"> + <div class="msg-content"> + <h2 class="title">${_("You're almost there!")}</h2> + <div class="copy"> + <p class='activation-message'>${Text(_( + "There's just one more step: Before you " + "enroll in a course, you need to activate " + "your account. We've sent an email message to " + "{email_start}{email}{email_end} with " + "instructions for activating your account. If " + "you don't receive this message, check your " + "spam folder." + )).format( + email_start=HTML("<strong>"), + email_end=HTML("</strong>"), + email=email, + )} + </p> + </div> + </div> + </div> +</div> \ No newline at end of file