diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index f990ca6060..8ec485a03a 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -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", { diff --git a/lms/djangoapps/pocs/migrations/0003_add_poc_membership_future_auto_enroll_flag.py b/lms/djangoapps/pocs/migrations/0003_add_poc_membership_future_auto_enroll_flag.py new file mode 100644 index 0000000000..27e844371d --- /dev/null +++ b/lms/djangoapps/pocs/migrations/0003_add_poc_membership_future_auto_enroll_flag.py @@ -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'] \ No newline at end of file diff --git a/lms/djangoapps/pocs/models.py b/lms/djangoapps/pocs/models.py index da06a9fc7b..19ef31e4eb 100644 --- a/lms/djangoapps/pocs/models.py +++ b/lms/djangoapps/pocs/models.py @@ -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): diff --git a/lms/djangoapps/pocs/tests/test_views.py b/lms/djangoapps/pocs/tests/test_views.py index bd6693328f..4f2edccffb 100644 --- a/lms/djangoapps/pocs/tests/test_views.py +++ b/lms/djangoapps/pocs/tests/test_views.py @@ -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) diff --git a/lms/djangoapps/pocs/utils.py b/lms/djangoapps/pocs/utils.py index f39017fcd3..9131c85342 100644 --- a/lms/djangoapps/pocs/utils.py +++ b/lms/djangoapps/pocs/utils.py @@ -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' diff --git a/lms/djangoapps/pocs/views.py b/lms/djangoapps/pocs/views.py index 964a79bc1d..62711aeb79 100644 --- a/lms/djangoapps/pocs/views.py +++ b/lms/djangoapps/pocs/views.py @@ -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: