MIT: CCX. Implement auto-enroll for CCX students
Based loosely on course enrollment model Ensure that registered users are 'active' when they are enrolled in a POC Respect the 'auto enroll' and 'email students' checkboxes in the UI Add an auto_enroll flag to the PocFutureMembership model so we can automatically enroll non-users when they have registered and activated their account. Build a future enrollment using the auto_enroll value from the request so we can ensure that non-existent users can be auto-enrolled Ensure that any user added by way of the one-at-a-time UI is automatically auto-enrolled Update tests with email sending to use the flag from the request Provide api on the PocMembership object to auto-enroll a newly active member in this poc. This method will delete the passed PocFutureMembership object and will automatically enroll the user in the POC named in that future membership as well as the MOOC from which it was created Conditionally activate poc memberships that are pending when a new registree first activates their account.
This commit is contained in:
@@ -1806,6 +1806,16 @@ def activate_account(request, key):
|
||||
if cea.auto_enroll:
|
||||
CourseEnrollment.enroll(student[0], cea.course_id)
|
||||
|
||||
# enroll student in any pending POCs he/she may have if auto_enroll flag is set
|
||||
if settings.FEATURES.get('PERSONAL_ONLINE_COURSES'):
|
||||
from pocs.models import PocMembership, PocFutureMembership
|
||||
pfms = PocFutureMembership.objects.filter(
|
||||
email=student[0].email
|
||||
)
|
||||
for pfm in pfms:
|
||||
if pfm.auto_enroll:
|
||||
PocMembership.auto_enroll(student[0], pfm)
|
||||
|
||||
resp = render_to_response(
|
||||
"registration/activation_complete.html",
|
||||
{
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# -*- 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 field 'PocFutureMembership.auto_enroll'
|
||||
db.add_column('pocs_pocfuturemembership', 'auto_enroll',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'PocFutureMembership.auto_enroll'
|
||||
db.delete_column('pocs_pocfuturemembership', 'auto_enroll')
|
||||
|
||||
|
||||
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'})
|
||||
},
|
||||
'pocs.personalonlinecourse': {
|
||||
'Meta': {'object_name': 'PersonalOnlineCourse'},
|
||||
'coach': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'pocs.pocfieldoverride': {
|
||||
'Meta': {'unique_together': "(('poc', 'location', 'field'),)", 'object_name': 'PocFieldOverride'},
|
||||
'field': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'location': ('xmodule_django.models.LocationKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
|
||||
'value': ('django.db.models.fields.TextField', [], {'default': "'null'"})
|
||||
},
|
||||
'pocs.pocfuturemembership': {
|
||||
'Meta': {'object_name': 'PocFutureMembership'},
|
||||
'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"})
|
||||
},
|
||||
'pocs.pocmembership': {
|
||||
'Meta': {'object_name': 'PocMembership'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
|
||||
'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['pocs']
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
|
||||
from student.models import CourseEnrollment, AlreadyEnrolledError
|
||||
from xmodule_django.models import CourseKeyField, LocationKeyField
|
||||
|
||||
|
||||
@@ -21,6 +22,20 @@ class PocMembership(models.Model):
|
||||
student = models.ForeignKey(User, db_index=True)
|
||||
active = models.BooleanField(default=False)
|
||||
|
||||
@classmethod
|
||||
def auto_enroll(cls, student=None, future_membership=None):
|
||||
assert student is not None and future_membership is not None
|
||||
membership = cls(
|
||||
poc=future_membership.poc, student=student, active=True
|
||||
)
|
||||
try:
|
||||
CourseEnrollment.enroll(student, future_membership.poc.course_id)
|
||||
except AlreadyEnrolledError:
|
||||
pass
|
||||
else:
|
||||
membership.save()
|
||||
future_membership.delete()
|
||||
|
||||
|
||||
class PocFutureMembership(models.Model):
|
||||
"""
|
||||
@@ -28,6 +43,7 @@ class PocFutureMembership(models.Model):
|
||||
"""
|
||||
poc = models.ForeignKey(PersonalOnlineCourse, db_index=True)
|
||||
email = models.CharField(max_length=255)
|
||||
auto_enroll = models.BooleanField(default=0)
|
||||
|
||||
|
||||
class PocFieldOverride(models.Model):
|
||||
|
||||
@@ -231,6 +231,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
data = {
|
||||
'enrollment-button': 'Enroll',
|
||||
'student-ids': u','.join([student.email, ]),
|
||||
'email-students': 'Notify-students-by-email',
|
||||
}
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -263,6 +264,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
data = {
|
||||
'enrollment-button': 'Unenroll',
|
||||
'student-ids': u','.join([student.email, ]),
|
||||
'email-students': 'Notify-students-by-email',
|
||||
}
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -292,6 +294,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
data = {
|
||||
'enrollment-button': 'Enroll',
|
||||
'student-ids': u','.join([test_email, ]),
|
||||
'email-students': 'Notify-students-by-email',
|
||||
}
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -323,6 +326,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
data = {
|
||||
'enrollment-button': 'Unenroll',
|
||||
'student-ids': u','.join([test_email, ]),
|
||||
'email-students': 'Notify-students-by-email',
|
||||
}
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -65,7 +65,14 @@ def enroll_email(poc, student_email, auto_enroll=False, email_students=False, em
|
||||
if previous_state.user:
|
||||
if not previous_state.in_poc:
|
||||
user = User.objects.get(email=student_email)
|
||||
membership = PocMembership(poc=poc, student=user)
|
||||
membership = PocMembership(
|
||||
poc=poc, student=user, active=True
|
||||
)
|
||||
membership.save()
|
||||
elif auto_enroll:
|
||||
# activate existing memberships
|
||||
membership = PocMembership.objects.get(student=user, poc=poc)
|
||||
membership.active = True
|
||||
membership.save()
|
||||
if email_students:
|
||||
email_params['message'] = 'enrolled_enroll'
|
||||
@@ -73,7 +80,9 @@ def enroll_email(poc, student_email, auto_enroll=False, email_students=False, em
|
||||
email_params['full_name'] = previous_state.full_name
|
||||
send_mail_to_student(student_email, email_params)
|
||||
else:
|
||||
membership = PocFutureMembership(poc=poc, email=student_email)
|
||||
membership = PocFutureMembership(
|
||||
poc=poc, auto_enroll=auto_enroll, email=student_email
|
||||
)
|
||||
membership.save()
|
||||
if email_students:
|
||||
email_params['message'] = 'allowed_enroll'
|
||||
|
||||
@@ -308,6 +308,8 @@ def poc_invite(request, course):
|
||||
action = request.POST.get('enrollment-button')
|
||||
identifiers_raw = request.POST.get('student-ids')
|
||||
identifiers = _split_input_list(identifiers_raw)
|
||||
auto_enroll = True if 'auto-enroll' in request.POST else False
|
||||
email_students = True if 'email-students' in request.POST else False
|
||||
for identifier in identifiers:
|
||||
user = None
|
||||
email = None
|
||||
@@ -320,9 +322,14 @@ def poc_invite(request, course):
|
||||
try:
|
||||
validate_email(email)
|
||||
if action == 'Enroll':
|
||||
enroll_email(poc, email, email_students=True)
|
||||
enroll_email(
|
||||
poc,
|
||||
email,
|
||||
auto_enroll=auto_enroll,
|
||||
email_students=email_students
|
||||
)
|
||||
if action == "Unenroll":
|
||||
unenroll_email(poc, email, email_students=True)
|
||||
unenroll_email(poc, email, email_students=email_students)
|
||||
except ValidationError:
|
||||
pass # maybe log this?
|
||||
url = reverse('poc_coach_dashboard', kwargs={'course_id': course.id})
|
||||
@@ -350,7 +357,8 @@ def poc_student_management(request, course):
|
||||
validate_email(email)
|
||||
if action == 'add':
|
||||
# by decree, no emails sent to students added this way
|
||||
enroll_email(poc, email, email_students=False)
|
||||
# by decree, any students added this way are auto_enrolled
|
||||
enroll_email(poc, email, auto_enroll=True, email_students=False)
|
||||
elif action == 'revoke':
|
||||
unenroll_email(poc, email, email_students=False)
|
||||
except ValidationError:
|
||||
|
||||
Reference in New Issue
Block a user