From 0361b50286d92fa62b3a323d5a98a9864c9ca951 Mon Sep 17 00:00:00 2001 From: Saleem Latif <saleem_ee@hotmail.com> Date: Wed, 12 Apr 2017 15:09:19 +0500 Subject: [PATCH] Change Account Activation UI on Dashboard --- .../student/tests/test_activate_account.py | 87 ++++++++++++++++++- common/djangoapps/student/views.py | 22 ++++- lms/envs/common.py | 3 + lms/static/sass/multicourse/_dashboard.scss | 29 +++++++ lms/templates/dashboard.html | 11 ++- .../account_activation_sidebar_notice.html | 34 ++++++++ .../registration/activate_account_notice.html | 41 +++++---- themes/edx.org/lms/templates/dashboard.html | 15 +++- 8 files changed, 209 insertions(+), 33 deletions(-) create mode 100644 lms/templates/registration/account_activation_sidebar_notice.html diff --git a/common/djangoapps/student/tests/test_activate_account.py b/common/djangoapps/student/tests/test_activate_account.py index 56f9b052b5c..8d4bcffa150 100644 --- a/common/djangoapps/student/tests/test_activate_account.py +++ b/common/djangoapps/student/tests/test_activate_account.py @@ -3,10 +3,12 @@ from mock import patch import unittest from django.conf import settings -from django.contrib.auth.models import User from django.test import TestCase, override_settings +from django.core.urlresolvers import reverse +from edxmako.shortcuts import render_to_string from student.models import Registration +from student.tests.factories import UserFactory @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @@ -17,13 +19,38 @@ class TestActivateAccount(TestCase): super(TestActivateAccount, self).setUp() self.username = "jack" self.email = "jack@fake.edx.org" - self.user = User.objects.create(username=self.username, email=self.email, is_active=False) + self.password = "test-password" + self.user = UserFactory.create( + username=self.username, email=self.email, password=self.password, is_active=False, + ) # Set Up Registration self.registration = Registration() self.registration.register(self.user) self.registration.save() + def login(self): + """ + Login with test user. + + Since, only active users can login, so we must activate the user before login. + This method does the following tasks in order, + 1. Stores user's active/in-active status in a variable. + 2. Makes sure user account is active. + 3. Authenticated user with the client. + 4. Reverts user's original active/in-active status. + """ + is_active = self.user.is_active + + # Make sure user is active before login + self.user.is_active = True + self.user.save() + self.client.login(username=self.username, password=self.password) + + # Revert user activation status + self.user.is_active = is_active + self.user.save() + def assert_no_tracking(self, mock_segment_identify): """ Assert that activate sets the flag but does not call segment. """ # Ensure that the user starts inactive @@ -76,3 +103,59 @@ class TestActivateAccount(TestCase): @patch('student.models.analytics.identify') 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. + + If logged in user has not activated his/her account, make sure that an + account activation message is displayed on dashboard sidebar. + """ + # Log in with test user. + self.login() + expected_message = render_to_string( + 'registration/account_activation_sidebar_notice.html', + {'email': self.user.email} + ) + + 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} + ) + 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, 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, html=True) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 2cdf3ffe095..381c51a9a38 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -685,9 +685,22 @@ def dashboard(request): course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True) - message = "" - if not user.is_active: - message = render_to_string( + 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} + ) + elif not user.is_active: + banner_account_activation_message = render_to_string( 'registration/activate_account_notice.html', {'email': user.email, 'platform_name': platform_name} ) @@ -819,7 +832,8 @@ def dashboard(request): 'redirect_message': redirect_message, 'course_enrollments': course_enrollments, 'course_optouts': course_optouts, - 'message': message, + '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, diff --git a/lms/envs/common.py b/lms/envs/common.py index a8b6d94d50f..fbba924d80b 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -377,6 +377,9 @@ FEATURES = { # Enable one click program purchase # See LEARNER-493 'ENABLE_ONE_CLICK_PROGRAM_PURCHASE': False, + + # Whether to display account activation notification on dashboard. + 'DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR': False, } # Ignore static asset files on import which match this pattern diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss index 5718bc4d722..1fae8f0982d 100644 --- a/lms/static/sass/multicourse/_dashboard.scss +++ b/lms/static/sass/multicourse/_dashboard.scss @@ -1227,6 +1227,35 @@ border-bottom-color: $m-gray-l4; } } + + // Warning for status verification + &.warning { + border-top: 3px solid #ffc01f !important; + + .status-title { + font-weight: 400 !important; + + .fa { + color: #ffc01f; + } + } + + .btn { + font-size: 16px; + line-height: 25.16px; + padding: 10px 10px; + border: 1px solid #0079bc; + color: #0079bc; + text-decoration: none; + display: block; + } + .btn:hover { + cursor: pointer; + color: #fff; + background-color: #0079bc; + } + + } } // status - verification diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index faf9ed0fae5..0e57bc39734 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -62,9 +62,10 @@ from openedx.core.djangolib.markup import HTML, Text </%block> <div class="dashboard-notifications" tabindex="-1"> - %if message: + + %if banner_account_activation_message: <div class="dashboard-banner"> - ${message | n, decode.utf8} + ${banner_account_activation_message | n, decode.utf8} </div> %endif @@ -137,6 +138,12 @@ from openedx.core.djangolib.markup import HTML, Text % endif </div> + %if sidebar_account_activation_message: + <div class="sidebar-notification"> + ${sidebar_account_activation_message | n, decode.utf8} + </div> + %endif + % if settings.FEATURES.get('ENABLE_DASHBOARD_SEARCH'): <div id="dashboard-search-bar" class="search-bar dashboard-search-bar" role="search" aria-label="Dashboard"> <form> diff --git a/lms/templates/registration/account_activation_sidebar_notice.html b/lms/templates/registration/account_activation_sidebar_notice.html new file mode 100644 index 00000000000..487a878e56b --- /dev/null +++ b/lms/templates/registration/account_activation_sidebar_notice.html @@ -0,0 +1,34 @@ +<%page expression_filter="h"/> +<%! +from django.utils.translation import ugettext as _ +from openedx.core.djangolib.markup import HTML, Text +%> +<div class="profile-sidebar" role="region" aria-label="Account Activation Info"> + <header class="profile"> + <h2 class="account-activation-title sr">${_("Account Activation Info")}: </h2> + </header> + <div class="user-info"> + <ul> + <li class="status status-verification warning" role="alert" aria-labelledby="title status-title" tabindex="1"> + <span class="title status-title"> + <i class="fa fa-exclamation-circle" aria-hidden="true"></i> + ${_("Activate your account!")} + </span> + <p class="status-note">${Text(_( + "Check your {email_start}{email}{email_end} inbox for an account activation link from edX. " + "If you need help, contact {link_start}edX Support{link_end}." + )).format( + email_start=HTML("<strong>"), + email_end=HTML("</strong>"), + email=email, + link_start=HTML("<a target='_blank' href='https://support.edx.org/hc/en-us/articles/227340127-Why-haven-t-I-received-my-activation-email-'>"), + link_end=HTML("</a>"), + )} + </p> + ## TODO: Add resend activation email functionality. + ## TODO: Implementation of this is part of ENT-353. + ## <a class="btn btn-neutral"><i class="fa fa-envelope-o"></i> Resend Activation Email </a> + </li> + </ul> + </div> +</div> diff --git a/lms/templates/registration/activate_account_notice.html b/lms/templates/registration/activate_account_notice.html index b09e40791d4..42811c03056 100644 --- a/lms/templates/registration/activate_account_notice.html +++ b/lms/templates/registration/activate_account_notice.html @@ -4,25 +4,24 @@ 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, - platform_name=platform_name - )} - </p> - </div> - </div> + <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> +</div> \ No newline at end of file diff --git a/themes/edx.org/lms/templates/dashboard.html b/themes/edx.org/lms/templates/dashboard.html index 13494aac144..75cda00e143 100644 --- a/themes/edx.org/lms/templates/dashboard.html +++ b/themes/edx.org/lms/templates/dashboard.html @@ -64,10 +64,11 @@ from openedx.core.djangoapps.theming import helpers as theming_helpers </%block> <div class="dashboard-notifications" tabindex="-1"> - %if message: - <section class="dashboard-banner"> - ${message | n, decode.utf8} - </section> + + %if banner_account_activation_message: + <div class="dashboard-banner"> + ${banner_account_activation_message | n, decode.utf8} + </div> %endif %if enrollment_message: @@ -142,6 +143,12 @@ from openedx.core.djangoapps.theming import helpers as theming_helpers </section> </main> + %if sidebar_account_activation_message: + <div class="sidebar-notification"> + ${sidebar_account_activation_message | n, decode.utf8} + </div> + %endif + % if settings.FEATURES.get('ENABLE_DASHBOARD_SEARCH'): <div id="dashboard-search-bar" class="search-bar dashboard-search-bar" role="search" aria-label="Dashboard"> <form> -- GitLab