diff --git a/common/djangoapps/student/management/commands/bulk_unenroll.py b/common/djangoapps/student/management/commands/bulk_unenroll.py index 70aa59687c..4faffa9aac 100644 --- a/common/djangoapps/student/management/commands/bulk_unenroll.py +++ b/common/djangoapps/student/management/commands/bulk_unenroll.py @@ -22,20 +22,31 @@ class Command(BaseCommand): It expect that the data will be provided in a csv file format with first row being the header and columns will be either one of the following: - username,course-id + | username | course_id | OR - course-id + | course_id | + + Example: + $ ... bulk_unenroll --csv_path=foo.csv + $ ... bulk_unenroll --csv_path=foo.csv --commit """ + commit = False def add_arguments(self, parser): - parser.add_argument('-p', '--csv_path', - metavar='csv_path', - dest='csv_path', - required=False, - help='Path to CSV file.') + parser.add_argument( + '-p', '--csv_path', + metavar='csv_path', + dest='csv_path', + required=False, + help='Path to CSV file.') + parser.add_argument( + '--commit', + action='store_true', + help='Save the changes, without this flag only a dry run will be performed and nothing will be changed') def handle(self, *args, **options): csv_path = options['csv_path'] + self.commit = options['commit'] if csv_path: with open(csv_path, 'rb') as csv_file: @@ -67,7 +78,13 @@ class Command(BaseCommand): if username: enrollments = enrollments.filter(user__username=username) - for enrollment in enrollments: - enrollment.update_enrollment(is_active=False, skip_refund=True) - logger.info("User [{}] have been successfully unenrolled from the course: {}" - .format(enrollment.user.username, course_key)) + logger.info("Processing [{}] with [{}] enrollments.".format(course_id, enrollments.count())) + + if self.commit: + for enrollment in enrollments: + enrollment.update_enrollment(is_active=False, skip_refund=True) + logger.info( + "User [{}] have been successfully unenrolled from the course: {}".format( + enrollment.user.username, course_key + ) + ) diff --git a/common/djangoapps/student/management/tests/test_bulk_unenroll.py b/common/djangoapps/student/management/tests/test_bulk_unenroll.py index d8f02ee3c4..664eddbfe5 100644 --- a/common/djangoapps/student/management/tests/test_bulk_unenroll.py +++ b/common/djangoapps/student/management/tests/test_bulk_unenroll.py @@ -58,7 +58,7 @@ class BulkUnenrollTests(SharedModuleStoreTestCase): csv = self._write_test_csv(csv, lines=["amy,test_course\n"]) with LogCapture(LOGGER_NAME) as log: - call_command("bulk_unenroll", "--csv_path={}".format(csv.name)) + call_command("bulk_unenroll", "--csv_path={}".format(csv.name), "--commit") expected_message = 'Invalid course id {}, skipping un-enrollement.'.\ format('test_course') @@ -76,10 +76,26 @@ class BulkUnenrollTests(SharedModuleStoreTestCase): with NamedTemporaryFile() as csv: csv = self._write_test_csv(csv, lines=lines) - call_command("bulk_unenroll", "--csv_path={}".format(csv.name)) + call_command("bulk_unenroll", "--csv_path={}".format(csv.name), "--commit") for enrollment in CourseEnrollment.objects.all(): self.assertEqual(enrollment.is_active, False) + def test_bulk_un_enroll_without_commit(self): + """ + Verify the ability to dry-run the command. + """ + lines = [ + enrollment.user.username + "," + + str(enrollment.course.id) + "\n" + for enrollment in self.enrollments + ] + with NamedTemporaryFile() as csv: + csv = self._write_test_csv(csv, lines=lines) + + call_command("bulk_unenroll", "--csv_path={}".format(csv.name)) + for enrollment in CourseEnrollment.objects.all(): + self.assertEqual(enrollment.is_active, True) + def test_bulk_unenroll_from_config_model(self): """Verify users are unenrolled using the command.""" lines = "user_id,username,email,course_id\n" @@ -90,7 +106,7 @@ class BulkUnenrollTests(SharedModuleStoreTestCase): csv_file = SimpleUploadedFile(name='test.csv', content=lines.encode('utf-8'), content_type='text/csv') BulkUnenrollConfiguration.objects.create(enabled=True, csv_file=csv_file) - call_command("bulk_unenroll") + call_command("bulk_unenroll", "--commit") for enrollment in CourseEnrollment.objects.all(): self.assertEqual(enrollment.is_active, False) @@ -101,14 +117,20 @@ class BulkUnenrollTests(SharedModuleStoreTestCase): csv_file = SimpleUploadedFile(name='test.csv', content=lines.encode('utf-8'), content_type='text/csv') BulkUnenrollConfiguration.objects.create(enabled=True, csv_file=csv_file) + course_id = self.enrollments[0].course.id with LogCapture(LOGGER_NAME) as log: - call_command("bulk_unenroll") + call_command("bulk_unenroll", "--commit") log.check( + ( + LOGGER_NAME, + 'INFO', + 'Processing [{}] with [1] enrollments.'.format(course_id), + ), ( LOGGER_NAME, 'INFO', 'User [{}] have been successfully unenrolled from the course: {}'.format( self.enrollments[0].username, self.enrollments[0].course.id ) - ) + ), )