def test_unenroll_non_user_student( self, view_name, send_email, outbox_count, student_form_input_name, button_tuple, identifier): """ Unenroll a list of students who are not users yet """ self.make_coach() course = CourseFactory.create() ccx = self.make_ccx() course_key = CCXLocator.from_course_locator(course.id, ccx.id) outbox = self.get_outbox() CourseEnrollmentAllowed(course_id=course_key, email=identifier) self.assertEqual(outbox, []) url = reverse( view_name, kwargs={'course_id': course_key} ) data = { button_tuple[0]: button_tuple[1], student_form_input_name: u','.join([identifier, ]), } if send_email: data['email-students'] = 'Notify-students-by-email' response = self.client.post(url, data=data, follow=True) self.assertEqual(response.status_code, 200) # we were redirected to our current location self.assertEqual(len(response.redirect_chain), 1) self.assertIn(302, response.redirect_chain[0]) self.assertEqual(len(outbox), outbox_count) self.assertFalse( CourseEnrollmentAllowed.objects.filter( course_id=course_key, email=identifier ).exists() )
def test_unenrollment_email_on(self): """ Do email on unenroll test """ course = self.course #Create invited, but not registered, user cea = CourseEnrollmentAllowed(email='*****@*****.**', course_id=course.id) cea.save() url = reverse('instructor_dashboard', kwargs={'course_id': course.id}) response = self.client.post(url, {'action': 'Unenroll multiple students', 'multiple_students': '[email protected], [email protected], [email protected]', 'email_students': 'on'}) #Check the page output self.assertContains(response, '<td>[email protected]</td>') self.assertContains(response, '<td>[email protected]</td>') self.assertContains(response, '<td>un-enrolled, email sent</td>') #Check the outbox self.assertEqual(len(mail.outbox), 3) self.assertEqual(mail.outbox[0].subject, 'You have been un-enrolled from MITx/999/Robot_Super_Course') self.assertEqual(mail.outbox[0].body, "Dear Student,\n\nYou have been un-enrolled from course MITx/999/Robot_Super_Course by a member of the course staff. " + "Please disregard the invitation previously sent.\n\n" + "----\nThis email was automatically sent from edx.org to [email protected]") self.assertEqual(mail.outbox[1].subject, 'You have been un-enrolled from MITx/999/Robot_Super_Course')
def test_unenroll_non_user_student(self): """unenroll a list of students who are not users yet """ test_email = "*****@*****.**" self.make_coach() course = CourseFactory.create() ccx = self.make_ccx() course_key = CCXLocator.from_course_locator(course.id, ccx.id) outbox = self.get_outbox() CourseEnrollmentAllowed(course_id=course_key, email=test_email) self.assertEqual(outbox, []) url = reverse('ccx_invite', kwargs={'course_id': course_key}) 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) # we were redirected to our current location self.assertEqual(len(response.redirect_chain), 1) self.assertTrue(302 in response.redirect_chain[0]) self.assertFalse( CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=test_email).exists())
def _set_up_invited_student(self, course, active=False, enrolled=True, course_mode=''): """ Helper function to create a user in the right state, invite them into the course, and update their course mode if needed. """ email = '*****@*****.**' user = UserFactory(username='******', first_name='Student', last_name='Person', email=email, is_active=active) # invite the user to the course cea = CourseEnrollmentAllowed(email=email, course_id=course.id, auto_enroll=True) cea.save() if enrolled: CourseEnrollment.enroll(user, course.id) if course_mode: course_enrollment = CourseEnrollment.objects.get( user=user, course_id=self.course.id) course_enrollment.mode = course_mode course_enrollment.save() return user
def _do_enroll_students(course, course_key, students, secure=False, overload=False, auto_enroll=False, email_students=False, is_shib_course=False): """ Do the actual work of enrolling multiple students, presented as a string of emails separated by commas or returns `course` is course object `course_key` id of course (a CourseKey) `students` string of student emails separated by commas or returns (a `str`) `overload` un-enrolls all existing students (a `boolean`) `auto_enroll` is user input preference (a `boolean`) `email_students` is user input preference (a `boolean`) """ new_students, new_students_lc = get_and_clean_student_list(students) status = dict([x, 'unprocessed'] for x in new_students) if overload: # delete all but staff todelete = CourseEnrollment.objects.filter(course_id=course_key) for enrollee in todelete: if not has_access(enrollee.user, 'staff', course) and enrollee.user.email.lower() not in new_students_lc: status[enrollee.user.email] = 'deleted' enrollee.deactivate() else: status[enrollee.user.email] = 'is staff' ceaset = CourseEnrollmentAllowed.objects.filter(course_id=course_key) for cea in ceaset: status[cea.email] = 'removed from pending enrollment list' ceaset.delete() if email_students: protocol = 'https' if secure else 'http' stripped_site_name = microsite.get_value( 'SITE_NAME', settings.SITE_NAME ) # TODO: Use request.build_absolute_uri rather than '{proto}://{site}{path}'.format # and check with the Services team that this works well with microsites registration_url = '{proto}://{site}{path}'.format( proto=protocol, site=stripped_site_name, path=reverse('register_user') ) course_url = '{proto}://{site}{path}'.format( proto=protocol, site=stripped_site_name, path=reverse('course_root', kwargs={'course_id': course_key.to_deprecated_string()}) ) # We can't get the url to the course's About page if the marketing site is enabled. course_about_url = None if not settings.FEATURES.get('ENABLE_MKTG_SITE', False): course_about_url = u'{proto}://{site}{path}'.format( proto=protocol, site=stripped_site_name, path=reverse('about_course', kwargs={'course_id': course_key.to_deprecated_string()}) ) # Composition of email email_data = { 'site_name': stripped_site_name, 'registration_url': registration_url, 'course': course, 'auto_enroll': auto_enroll, 'course_url': course_url, 'course_about_url': course_about_url, 'is_shib_course': is_shib_course } for student in new_students: try: user = User.objects.get(email=student) except User.DoesNotExist: # Student not signed up yet, put in pending enrollment allowed table cea = CourseEnrollmentAllowed.objects.filter(email=student, course_id=course_key) # If enrollmentallowed already exists, update auto_enroll flag to however it was set in UI # Will be 0 or 1 records as there is a unique key on email + course_id if cea: cea[0].auto_enroll = auto_enroll cea[0].save() status[student] = 'user does not exist, enrollment already allowed, pending with auto enrollment ' \ + ('on' if auto_enroll else 'off') continue # EnrollmentAllowed doesn't exist so create it cea = CourseEnrollmentAllowed(email=student, course_id=course_key, auto_enroll=auto_enroll) cea.save() status[student] = 'user does not exist, enrollment allowed, pending with auto enrollment ' \ + ('on' if auto_enroll else 'off') if email_students: # User is allowed to enroll but has not signed up yet email_data['email_address'] = student email_data['message'] = 'allowed_enroll' send_mail_ret = send_mail_to_student(student, email_data) status[student] += (', email sent' if send_mail_ret else '') continue # Student has already registered if CourseEnrollment.is_enrolled(user, course_key): status[student] = 'already enrolled' continue try: # Not enrolled yet CourseEnrollment.enroll(user, course_key) status[student] = 'added' if email_students: # User enrolled for first time, populate dict with user specific info email_data['email_address'] = student email_data['full_name'] = user.profile.name email_data['message'] = 'enrolled_enroll' send_mail_ret = send_mail_to_student(student, email_data) status[student] += (', email sent' if send_mail_ret else '') except Exception: # pylint: disable=broad-except status[student] = 'rejected' datatable = {'header': ['StudentEmail', 'action']} datatable['data'] = [[x, status[x]] for x in sorted(status)] datatable['title'] = _('Enrollment of students') def sf(stat): return [x for x in status if status[x] == stat] data = dict(added=sf('added'), rejected=sf('rejected') + sf('exists'), deleted=sf('deleted'), datatable=datatable) return data