diff --git a/cms/templates/registration/activation_invalid.html b/cms/templates/registration/activation_invalid.html
new file mode 100644
index 0000000000..5160b46449
--- /dev/null
+++ b/cms/templates/registration/activation_invalid.html
@@ -0,0 +1,29 @@
+<%page expression_filter="h"/>
+<%inherit file="../base.html" />
+<%namespace name='static' file='../static_content.html'/>
+<%!
+from django.utils.translation import ugettext as _
+from django.core.urlresolvers import reverse
+from openedx.core.djangolib.markup import HTML, Text
+%>
+
+<%block name="content">
+
+
+
+ ${_("Activation Invalid")}
+
+
+ ${Text(_("Something went wrong. Email programs sometimes split URLs "
+ "into two lines, so make sure the URL you're using is " "formatted correctly. If you still have issues, send us "
+ "an email message at " "{email_start}{email}{email_end}.")).format(
+ email_start=HTML('').format(settings.BUGS_EMAIL),
+ email=settings.BUGS_EMAIL,
+ email_end=HTML('')
+ )}
+
+ ${Text(_('Return to the {link_start}home page{link_end}.')).format(
+ link_start=HTML(''), link_end=HTML(''))}
+
+
+%block>
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 3a396c82cb..78d9f1311b 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -90,6 +90,7 @@ from openedx.core.djangoapps.external_auth.login_and_register import (
register as external_auth_register
)
from openedx.core.djangoapps import monitoring_utils
+from openedx.core.djangolib.markup import HTML, Text
import track.views
@@ -721,6 +722,11 @@ def dashboard(request):
enterprise_message = get_dashboard_consent_notification(request, user, course_enrollments)
+ # Account activation message
+ account_activation_messages = [
+ message for message in messages.get_messages(request) if 'account-activation' in message.tags
+ ]
+
# Global staff can see what courses errored on their dashboard
staff_access = False
errored_courses = {}
@@ -844,6 +850,7 @@ def dashboard(request):
'enterprise_message': enterprise_message,
'enrollment_message': enrollment_message,
'redirect_message': redirect_message,
+ 'account_activation_messages': account_activation_messages,
'course_enrollments': course_enrollments,
'course_optouts': course_optouts,
'banner_account_activation_message': banner_account_activation_message,
@@ -2285,31 +2292,83 @@ def auto_auth(request):
@ensure_csrf_cookie
def activate_account(request, key):
"""When link in activation e-mail is clicked"""
- regs = Registration.objects.filter(activation_key=key)
- if len(regs) == 1:
+
+ # If request is in Studio call the appropriate view
+ if theming_helpers.get_project_root_name().lower() == u'cms':
+ return activate_account_studio(request, key)
+
+ try:
+ registration = Registration.objects.get(activation_key=key)
+ except (Registration.DoesNotExist, Registration.MultipleObjectsReturned):
+ messages.error(
+ request,
+ Text(_(
+ '{html_start}Your account could not be activated{html_end}'
+ 'Something went wrong, please contact support to resolve this issue.'
+ )).format(
+ support_url=configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK),
+ html_start=HTML('
'),
+ html_end=HTML('
'),
+ ),
+ extra_tags='account-activation icon'
+ )
+ else:
+ if not registration.user.is_active:
+ registration.activate()
+ # Add account activation success message for display later
+ messages.success(
+ request,
+ Text(_('{html_start}Success{html_end} You have activated your account.')).format(
+ html_start=HTML(''),
+ html_end=HTML('
'),
+ ),
+ extra_tags='account-activation icon',
+ )
+ else:
+ messages.info(
+ request,
+ Text(_('{html_start}This account has already been activated.{html_end}')).format(
+ html_start=HTML(''),
+ html_end=HTML('
'),
+ ),
+ extra_tags='account-activation icon',
+ )
+
+ # Enroll student in any pending courses he/she may have if auto_enroll flag is set
+ _enroll_user_in_pending_courses(registration.user)
+
+ return redirect('dashboard')
+
+
+@ensure_csrf_cookie
+def activate_account_studio(request, key):
+ """
+ When link in activation e-mail is clicked and the link belongs to studio.
+ """
+ try:
+ registration = Registration.objects.get(activation_key=key)
+ except (Registration.DoesNotExist, Registration.MultipleObjectsReturned):
+ return render_to_response(
+ "registration/activation_invalid.html",
+ {'csrf': csrf(request)['csrf_token']}
+ )
+ else:
user_logged_in = request.user.is_authenticated()
already_active = True
- if not regs[0].user.is_active:
- regs[0].activate()
+ if not registration.user.is_active:
+ registration.activate()
already_active = False
# Enroll student in any pending courses he/she may have if auto_enroll flag is set
- _enroll_user_in_pending_courses(regs[0].user)
+ _enroll_user_in_pending_courses(registration.user)
- resp = render_to_response(
+ return render_to_response(
"registration/activation_complete.html",
{
'user_logged_in': user_logged_in,
'already_active': already_active
}
)
- return resp
- if len(regs) == 0:
- return render_to_response(
- "registration/activation_invalid.html",
- {'csrf': csrf(request)['csrf_token']}
- )
- return HttpResponseServerError(_("Unknown error. Please e-mail us to let us know how it happened."))
@csrf_exempt
diff --git a/lms/djangoapps/courseware/tests/helpers.py b/lms/djangoapps/courseware/tests/helpers.py
index 6aaf154b99..4c15c6d39b 100644
--- a/lms/djangoapps/courseware/tests/helpers.py
+++ b/lms/djangoapps/courseware/tests/helpers.py
@@ -3,6 +3,7 @@ Helpers for courseware tests.
"""
import json
+from django.contrib import messages
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test import TestCase
@@ -53,6 +54,14 @@ class LoginEnrollmentTestCase(TestCase):
)
return response
+ def assert_account_activated(self, url, method="GET", **kwargs):
+ make_request = getattr(self.client, method.lower())
+ response = make_request(url, **kwargs)
+ message_list = list(messages.get_messages(response.wsgi_request))
+ self.assertEqual(len(message_list), 1)
+ self.assertIn("success", message_list[0].tags)
+ self.assertTrue("You have activated your account." in message_list[0].message)
+
# ============ User creation and login ==============
def login(self, email, password):
@@ -102,7 +111,7 @@ class LoginEnrollmentTestCase(TestCase):
activation_key = Registration.objects.get(user__email=email).activation_key
# and now we try to activate
url = reverse('activate', kwargs={'key': activation_key})
- self.assert_request_status_code(200, url)
+ self.assert_account_activated(url)
# Now make sure that the user is now actually activated
user = User.objects.get(email=email)
self.assertTrue(user.is_active)
diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py
index 85b892983e..9de1a6e56b 100644
--- a/lms/djangoapps/courseware/tests/test_course_info.py
+++ b/lms/djangoapps/courseware/tests/test_course_info.py
@@ -367,7 +367,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
self.assertEqual(resp.status_code, 200)
def test_num_queries_instructor_paced(self):
- self.fetch_course_info_with_queries(self.instructor_paced_course, 20, 4)
+ self.fetch_course_info_with_queries(self.instructor_paced_course, 21, 4)
def test_num_queries_self_paced(self):
- self.fetch_course_info_with_queries(self.self_paced_course, 20, 4)
+ self.fetch_course_info_with_queries(self.self_paced_course, 21, 4)
diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss
index 1fae8f0982..f002f310c8 100644
--- a/lms/static/sass/multicourse/_dashboard.scss
+++ b/lms/static/sass/multicourse/_dashboard.scss
@@ -1420,3 +1420,80 @@ a.fade-cover{
}
}
+// Dashboard alert messages
+.activation-message-container {
+ @include clearfix();
+ margin: 0 auto 0;
+ padding-top: ($baseline/2);
+ max-width: grid-width(12);
+ min-width: 760px;
+ width: flex-grid(12);
+}
+
+.account-activation {
+
+ .message-copy {
+ position: relative;
+ left: 2em;
+ padding: 1em;
+ }
+
+ .message-title {
+ margin-bottom: 6px;
+ font-weight: 600;
+ }
+
+ &.info {
+ color: $palette-info-text;
+ background-color: $palette-info-back;
+ border: $palette-info-border 1px solid;
+ padding: 5px;
+
+ .message-title{
+ margin-bottom: 0;
+ }
+
+ &.icon .message-copy:before {
+ position: absolute;
+ left: -1em;
+ content: "\f05a"; // fa-info-circle
+ font-size: 1.5em;
+ padding: 0 2px;
+ font-family: FontAwesome;
+ }
+ }
+
+ &.success {
+ color: $palette-success-text;
+ background-color: $palette-success-back;
+ border: $palette-success-border 1px solid;
+
+ &.icon .message-copy:before {
+ position: absolute;
+ left: -1em;
+ content: "\f00c"; // fa-check
+ font-size: 1.5em;
+ padding: 0 2px;
+ font-family: FontAwesome;
+ }
+ }
+
+ &.error {
+ color: $palette-error-text;
+ background-color: $palette-error-back;
+ border: $palette-error-border 1px solid;
+
+ &.icon .message-copy:before {
+ position: absolute;
+ left: -1em;
+ content: "\f06a"; // fa-exclamation-circle
+ font-size: 1.5em;
+ padding: 0 2px;
+ font-family: FontAwesome;
+ }
+
+ a {
+ text-decoration: underline;
+ }
+ }
+}
diff --git a/lms/static/sass/partials/base/_variables.scss b/lms/static/sass/partials/base/_variables.scss
index a17f900f2c..48c5d2be9c 100644
--- a/lms/static/sass/partials/base/_variables.scss
+++ b/lms/static/sass/partials/base/_variables.scss
@@ -514,6 +514,17 @@ $dashboard-profile-color: rgb(252,252,252) !default;
$dot-color: rgb(221, 221, 221) !default;
$dashboard-course-cover-border: rgb(221, 221, 221) !default;
+// dashboard notification messages
+$palette-info-border: #cce3f0;
+$palette-info-back: #f2f8fb;
+$palette-info-text: #0075b4;
+$palette-error-border: #ebccd1;
+$palette-error-back: #feeced;
+$palette-error-text: #b20610;
+$palette-success-border: #b9edb9;
+$palette-success-back: #ecfaec;
+$palette-success-text: #008100;
+
// course elements
$content-wrapper-bg: $white !default;
$course-bg-color: $uxpl-grayscale-x-back !default;
diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html
index 0e57bc3973..72bc6076b5 100644
--- a/lms/templates/dashboard.html
+++ b/lms/templates/dashboard.html
@@ -80,6 +80,19 @@ from openedx.core.djangolib.markup import HTML, Text
${ enterprise_message | n, decode.utf8 }
%endif
+
+ %if account_activation_messages:
+
+ % for account_activation_message in account_activation_messages:
+
+ % endfor
+
+ %endif
+
diff --git a/lms/templates/registration/activation_complete.html b/lms/templates/registration/activation_complete.html
deleted file mode 100644
index b49353afbe..0000000000
--- a/lms/templates/registration/activation_complete.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<%page expression_filter="h"/>
-<%inherit file="../main.html" />
-<%namespace name='static' file='../static_content.html'/>
-<%!
-from django.utils.translation import ugettext as _
-from django.core.urlresolvers import reverse
-from openedx.core.djangolib.markup import HTML, Text
-%>
-
-
-
-
- %if not already_active:
- ${_("Account Activated")}
- %else:
- ${_("Account already active")}
- %endif
-
-
-
- %if not already_active:
- ${_("Thanks for activating your account.")}
- %else:
- ${_("This account has already been activated.")}
- %endif
-
- %if user_logged_in:
- ${Text(_("Visit your {link_start}dashboard{link_end} to see your courses.")).format(
- link_start=HTML('').format(url=reverse('dashboard')), link_end=HTML(''))}
- %else:
- ${Text(_("You can now {link_start}sign in{link_end}.")).format(
- link_start=HTML('').format(url=reverse('signin_user')), link_end=HTML(''))}
- %endif
-
-
-
diff --git a/lms/templates/registration/activation_invalid.html b/lms/templates/registration/activation_invalid.html
deleted file mode 100644
index 1b54d6c2a3..0000000000
--- a/lms/templates/registration/activation_invalid.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<%page expression_filter="h"/>
-<%inherit file="../main.html" />
-<%namespace name='static' file='../static_content.html'/>
-<%!
-from django.utils.translation import ugettext as _
-from django.core.urlresolvers import reverse
-from openedx.core.djangolib.markup import HTML, Text
-%>
-
-
-
-
- ${_("Activation Invalid")}
-
-
- ${Text(_("Something went wrong. Email programs sometimes split URLs "
- "into two lines, so make sure the URL you're using is " "formatted correctly. If you still have issues, send us "
- "an email message at " "{email_start}{email}{email_end}.")).format(
- email_start=HTML('').format(settings.BUGS_EMAIL),
- email=settings.BUGS_EMAIL,
- email_end=HTML('')
- )}
-
- ${Text(_('Return to the {link_start}home page{link_end}.')).format(
- link_start=HTML(''), link_end=HTML(''))}
-
-
diff --git a/themes/edx.org/lms/templates/dashboard.html b/themes/edx.org/lms/templates/dashboard.html
index 75cda00e14..2e7733a2be 100644
--- a/themes/edx.org/lms/templates/dashboard.html
+++ b/themes/edx.org/lms/templates/dashboard.html
@@ -82,6 +82,19 @@ from openedx.core.djangoapps.theming import helpers as theming_helpers
${ enterprise_message | n, decode.utf8 }
%endif
+
+ %if account_activation_messages:
+
+ % for account_activation_message in account_activation_messages:
+
+ % endfor
+
+ %endif
+