Merge pull request #5420 from edx/sanchez/enrollment-success-message
Add new enrollment message to the dashboard
This commit is contained in:
@@ -157,7 +157,7 @@ class ChooseModeView(View):
|
||||
# it doesn't matter, but it will avoid hitting the database.
|
||||
if requested_mode == 'honor':
|
||||
CourseEnrollment.enroll(user, course_key, requested_mode)
|
||||
return redirect('dashboard')
|
||||
return redirect(reverse('dashboard'))
|
||||
|
||||
mode_info = allowed_modes[requested_mode]
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'''
|
||||
django admin pages for courseware model
|
||||
'''
|
||||
from config_models.admin import ConfigurationModelAdmin
|
||||
|
||||
from student.models import UserProfile, UserTestGroup, CourseEnrollmentAllowed
|
||||
from student.models import UserProfile, UserTestGroup, CourseEnrollmentAllowed, DashboardConfiguration
|
||||
from student.models import CourseEnrollment, Registration, PendingNameChange, CourseAccessRole, CourseAccessRoleAdmin
|
||||
from ratelimitbackend import admin
|
||||
|
||||
@@ -19,3 +20,5 @@ admin.site.register(Registration)
|
||||
admin.site.register(PendingNameChange)
|
||||
|
||||
admin.site.register(CourseAccessRole, CourseAccessRoleAdmin)
|
||||
|
||||
admin.site.register(DashboardConfiguration, ConfigurationModelAdmin)
|
||||
|
||||
@@ -6,6 +6,7 @@ from django.contrib.auth.models import User
|
||||
from django.contrib.auth.forms import PasswordResetForm
|
||||
from django.contrib.auth.hashers import UNUSABLE_PASSWORD
|
||||
|
||||
|
||||
class PasswordResetFormNoActive(PasswordResetForm):
|
||||
def clean_email(self):
|
||||
"""
|
||||
@@ -21,4 +22,4 @@ class PasswordResetFormNoActive(PasswordResetForm):
|
||||
if any((user.password == UNUSABLE_PASSWORD)
|
||||
for user in self.users_cache):
|
||||
raise forms.ValidationError(self.error_messages['unusable'])
|
||||
return email
|
||||
return email
|
||||
@@ -0,0 +1,179 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'DashboardConfiguration'
|
||||
db.create_table('student_dashboardconfiguration', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('change_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('changed_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, on_delete=models.PROTECT)),
|
||||
('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('recent_enrollment_time_delta', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal('student', ['DashboardConfiguration'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'DashboardConfiguration'
|
||||
db.delete_table('student_dashboardconfiguration')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.anonymoususerid': {
|
||||
'Meta': {'object_name': 'AnonymousUserId'},
|
||||
'anonymous_user_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.courseaccessrole': {
|
||||
'Meta': {'unique_together': "(('user', 'org', 'course_id', 'role'),)", 'object_name': 'CourseAccessRole'},
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'org': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'blank': 'True'}),
|
||||
'role': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.courseenrollment': {
|
||||
'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'mode': ('django.db.models.fields.CharField', [], {'default': "'honor'", 'max_length': '100'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.courseenrollmentallowed': {
|
||||
'Meta': {'unique_together': "(('email', 'course_id'),)", 'object_name': 'CourseEnrollmentAllowed'},
|
||||
'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
|
||||
'email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'student.dashboardconfiguration': {
|
||||
'Meta': {'object_name': 'DashboardConfiguration'},
|
||||
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'recent_enrollment_time_delta': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
|
||||
},
|
||||
'student.loginfailures': {
|
||||
'Meta': {'object_name': 'LoginFailures'},
|
||||
'failure_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'lockout_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.passwordhistory': {
|
||||
'Meta': {'object_name': 'PasswordHistory'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'time_set': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.pendingemailchange': {
|
||||
'Meta': {'object_name': 'PendingEmailChange'},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'new_email': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.pendingnamechange': {
|
||||
'Meta': {'object_name': 'PendingNameChange'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'new_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'rationale': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'allow_certificate': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'city': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
|
||||
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
|
||||
'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
|
||||
'goals': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'level_of_education': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
|
||||
'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'student.usersignupsource': {
|
||||
'Meta': {'object_name': 'UserSignupSource'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'site': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.userstanding': {
|
||||
'Meta': {'object_name': 'UserStanding'},
|
||||
'account_status': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'standing_last_changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'standing'", 'unique': 'True', 'to': "orm['auth.User']"})
|
||||
},
|
||||
'student.usertestgroup': {
|
||||
'Meta': {'object_name': 'UserTestGroup'},
|
||||
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
@@ -32,6 +32,7 @@ from django.dispatch import receiver, Signal
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.translation import ugettext_noop
|
||||
from django_countries import CountryField
|
||||
from config_models.models import ConfigurationModel
|
||||
from track import contexts
|
||||
from eventtracking import tracker
|
||||
from importlib import import_module
|
||||
@@ -1388,3 +1389,20 @@ def enforce_single_login(sender, request, user, signal, **kwargs): # pylint:
|
||||
else:
|
||||
key = None
|
||||
user.profile.set_login_session(key)
|
||||
|
||||
|
||||
class DashboardConfiguration(ConfigurationModel):
|
||||
"""Dashboard Configuration settings.
|
||||
|
||||
Includes configuration options for the dashboard, which impact behavior and rendering for the application.
|
||||
|
||||
"""
|
||||
recent_enrollment_time_delta = models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="The number of seconds in which a new enrollment is considered 'recent'. "
|
||||
"Used to display notifications."
|
||||
)
|
||||
|
||||
@property
|
||||
def recent_enrollment_seconds(self):
|
||||
return self.recent_enrollment_time_delta
|
||||
|
||||
127
common/djangoapps/student/tests/test_recent_enrollments.py
Normal file
127
common/djangoapps/student/tests/test_recent_enrollments.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
Tests for the recently enrolled messaging within the Dashboard.
|
||||
"""
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import Client
|
||||
from opaque_keys.edx import locator
|
||||
from pytz import UTC
|
||||
import unittest
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from student.models import CourseEnrollment, DashboardConfiguration
|
||||
from student.views import get_course_enrollment_pairs, _get_recently_enrolled_courses
|
||||
|
||||
|
||||
class TestRecentEnrollments(ModuleStoreTestCase):
|
||||
"""
|
||||
Unit tests for getting the list of courses for a logged in user
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Add a student
|
||||
"""
|
||||
super(TestRecentEnrollments, self).setUp()
|
||||
self.student = UserFactory()
|
||||
|
||||
# Old Course
|
||||
old_course_location = locator.CourseLocator('Org0', 'Course0', 'Run0')
|
||||
course, enrollment = self._create_course_and_enrollment(old_course_location)
|
||||
enrollment.created = datetime.datetime(1900, 12, 31, 0, 0, 0, 0)
|
||||
enrollment.save()
|
||||
|
||||
# New Course
|
||||
course_location = locator.CourseLocator('Org1', 'Course1', 'Run1')
|
||||
self._create_course_and_enrollment(course_location)
|
||||
|
||||
def _create_course_and_enrollment(self, course_location):
|
||||
""" Creates a course and associated enrollment. """
|
||||
course = CourseFactory.create(
|
||||
org=course_location.org,
|
||||
number=course_location.course,
|
||||
run=course_location.run
|
||||
)
|
||||
enrollment = CourseEnrollment.enroll(self.student, course.id)
|
||||
return course, enrollment
|
||||
|
||||
def test_recently_enrolled_courses(self):
|
||||
"""
|
||||
Test if the function for filtering recent enrollments works appropriately.
|
||||
"""
|
||||
config = DashboardConfiguration(recent_enrollment_time_delta=60)
|
||||
config.save()
|
||||
# get courses through iterating all courses
|
||||
courses_list = list(get_course_enrollment_pairs(self.student, None, []))
|
||||
self.assertEqual(len(courses_list), 2)
|
||||
|
||||
recent_course_list = _get_recently_enrolled_courses(courses_list)
|
||||
self.assertEqual(len(recent_course_list), 1)
|
||||
|
||||
def test_zero_second_delta(self):
|
||||
"""
|
||||
Tests that the recent enrollment list is empty if configured to zero seconds.
|
||||
"""
|
||||
config = DashboardConfiguration(recent_enrollment_time_delta=0)
|
||||
config.save()
|
||||
courses_list = list(get_course_enrollment_pairs(self.student, None, []))
|
||||
self.assertEqual(len(courses_list), 2)
|
||||
|
||||
recent_course_list = _get_recently_enrolled_courses(courses_list)
|
||||
self.assertEqual(len(recent_course_list), 0)
|
||||
|
||||
def test_enrollments_sorted_most_recent(self):
|
||||
"""
|
||||
Test that the list of newly created courses are properly sorted to show the most
|
||||
recent enrollments first.
|
||||
|
||||
"""
|
||||
config = DashboardConfiguration(recent_enrollment_time_delta=600)
|
||||
config.save()
|
||||
|
||||
# Create a number of new enrollments and courses, and force their creation behind
|
||||
# the first enrollment
|
||||
course_location = locator.CourseLocator('Org2', 'Course2', 'Run2')
|
||||
_, enrollment2 = self._create_course_and_enrollment(course_location)
|
||||
enrollment2.created = datetime.datetime.now(UTC) - datetime.timedelta(seconds=5)
|
||||
enrollment2.save()
|
||||
|
||||
course_location = locator.CourseLocator('Org3', 'Course3', 'Run3')
|
||||
_, enrollment3 = self._create_course_and_enrollment(course_location)
|
||||
enrollment3.created = datetime.datetime.now(UTC) - datetime.timedelta(seconds=10)
|
||||
enrollment3.save()
|
||||
|
||||
course_location = locator.CourseLocator('Org4', 'Course4', 'Run4')
|
||||
_, enrollment4 = self._create_course_and_enrollment(course_location)
|
||||
enrollment4.created = datetime.datetime.now(UTC) - datetime.timedelta(seconds=15)
|
||||
enrollment4.save()
|
||||
|
||||
course_location = locator.CourseLocator('Org5', 'Course5', 'Run5')
|
||||
_, enrollment5 = self._create_course_and_enrollment(course_location)
|
||||
enrollment5.created = datetime.datetime.now(UTC) - datetime.timedelta(seconds=20)
|
||||
enrollment5.save()
|
||||
|
||||
courses_list = list(get_course_enrollment_pairs(self.student, None, []))
|
||||
self.assertEqual(len(courses_list), 6)
|
||||
|
||||
recent_course_list = _get_recently_enrolled_courses(courses_list)
|
||||
self.assertEqual(len(recent_course_list), 5)
|
||||
|
||||
self.assertEqual(recent_course_list[1][1], enrollment2)
|
||||
self.assertEqual(recent_course_list[2][1], enrollment3)
|
||||
self.assertEqual(recent_course_list[3][1], enrollment4)
|
||||
self.assertEqual(recent_course_list[4][1], enrollment5)
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
def test_dashboard_rendering(self):
|
||||
"""
|
||||
Tests that the dashboard renders the recent enrollment messages appropriately.
|
||||
"""
|
||||
config = DashboardConfiguration(recent_enrollment_time_delta=600)
|
||||
config.save()
|
||||
self.client = Client()
|
||||
self.client.login(username=self.student.username, password='test')
|
||||
response = self.client.get(reverse("dashboard"))
|
||||
self.assertContains(response, "You have successfully enrolled in")
|
||||
@@ -46,8 +46,8 @@ from student.models import (
|
||||
Registration, UserProfile, PendingNameChange,
|
||||
PendingEmailChange, CourseEnrollment, unique_id_for_user,
|
||||
CourseEnrollmentAllowed, UserStanding, LoginFailures,
|
||||
create_comments_service_user, PasswordHistory, UserSignupSource
|
||||
)
|
||||
create_comments_service_user, PasswordHistory, UserSignupSource,
|
||||
DashboardConfiguration)
|
||||
from student.forms import PasswordResetFormNoActive
|
||||
|
||||
from verify_student.models import SoftwareSecurePhotoVerification, MidcourseReverificationWindow
|
||||
@@ -471,6 +471,10 @@ def dashboard(request):
|
||||
# enrollments, because it could have been a data push snafu.
|
||||
course_enrollment_pairs = list(get_course_enrollment_pairs(user, course_org_filter, org_filter_out_set))
|
||||
|
||||
# Check to see if the student has recently enrolled in a course. If so, display a notification message confirming
|
||||
# the enrollment.
|
||||
enrollment_message = _create_recent_enrollment_message(course_enrollment_pairs)
|
||||
|
||||
course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True)
|
||||
|
||||
message = ""
|
||||
@@ -551,6 +555,7 @@ def dashboard(request):
|
||||
current_language = settings.LANGUAGE_DICT[settings.LANGUAGE_CODE]
|
||||
|
||||
context = {
|
||||
'enrollment_message': enrollment_message,
|
||||
'course_enrollment_pairs': course_enrollment_pairs,
|
||||
'course_optouts': course_optouts,
|
||||
'message': message,
|
||||
@@ -586,6 +591,49 @@ def dashboard(request):
|
||||
return render_to_response('dashboard.html', context)
|
||||
|
||||
|
||||
def _create_recent_enrollment_message(course_enrollment_pairs):
|
||||
"""Builds a recent course enrollment message
|
||||
|
||||
Constructs a new message template based on any recent course enrollments for the student.
|
||||
|
||||
Args:
|
||||
course_enrollment_pairs (list): A list of tuples containing courses, and the associated enrollment information.
|
||||
|
||||
Returns:
|
||||
A string representing the HTML message output from the message template.
|
||||
|
||||
"""
|
||||
recent_course_enrollment_pairs = _get_recently_enrolled_courses(course_enrollment_pairs)
|
||||
if recent_course_enrollment_pairs:
|
||||
return render_to_string(
|
||||
'enrollment/course_enrollment_message.html',
|
||||
{'recent_course_enrollment_pairs': recent_course_enrollment_pairs,}
|
||||
)
|
||||
|
||||
|
||||
def _get_recently_enrolled_courses(course_enrollment_pairs):
|
||||
"""Checks to see if the student has recently enrolled in courses.
|
||||
|
||||
Checks to see if any of the enrollments in the course_enrollment_pairs have been recently created and activated.
|
||||
|
||||
Args:
|
||||
course_enrollment_pairs (list): A list of tuples containing courses, and the associated enrollment information.
|
||||
|
||||
Returns:
|
||||
A list of tuples for the course and enrollment.
|
||||
|
||||
"""
|
||||
seconds = DashboardConfiguration.current().recent_enrollment_time_delta
|
||||
sorted_list = sorted(course_enrollment_pairs, key=lambda created: created[1].created, reverse=True)
|
||||
time_delta = (datetime.datetime.now(UTC) - datetime.timedelta(seconds=seconds))
|
||||
return [
|
||||
(course, enrollment) for course, enrollment in sorted_list
|
||||
# If the enrollment has no created date, we are explicitly excluding the course
|
||||
# from the list of recent enrollments.
|
||||
if enrollment.is_active and enrollment.created > time_delta
|
||||
]
|
||||
|
||||
|
||||
def try_change_enrollment(request):
|
||||
"""
|
||||
This method calls change_enrollment if the necessary POST
|
||||
|
||||
@@ -192,6 +192,10 @@
|
||||
</section>
|
||||
%endif
|
||||
|
||||
%if enrollment_message:
|
||||
${enrollment_message}
|
||||
%endif
|
||||
|
||||
% if duplicate_provider:
|
||||
<section class="dashboard-banner third-party-auth">
|
||||
## Translators: this message is displayed when a user tries to link their account with a third-party authentication provider (for example, Google or LinkedIn) with a given edX account, but their third-party account is already associated with another edX account. provider_name is the name of the third-party authentication provider, and platform_name is the name of the edX deployment.
|
||||
|
||||
6
lms/templates/enrollment/course_enrollment_message.html
Normal file
6
lms/templates/enrollment/course_enrollment_message.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
% for course, enrollment in recent_course_enrollment_pairs:
|
||||
<section class="dashboard-banner">
|
||||
<p class='activation-message'>${_("You have successfully enrolled in {enrolled_course}.").format(enrolled_course=course.display_name)}</p>
|
||||
</section>
|
||||
% endfor
|
||||
Reference in New Issue
Block a user