Skip to content

Commit 75aa91d

Browse files
Agrendalathxitij2000
authored andcommitted
fix: support files with a unicode signature in the Instructor Dashboard API
Without this, files with BOM (byte order mark; generated e.g., by Microsoft Excel) cannot be read properly. (cherry picked from commit 7d8a502)
1 parent c410212 commit 75aa91d

File tree

2 files changed

+11
-27
lines changed

2 files changed

+11
-27
lines changed

lms/djangoapps/instructor/tests/test_api.py

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@ def test_instructor_level(self):
590590

591591

592592
@patch.dict(settings.FEATURES, {'ALLOW_AUTOMATED_SIGNUPS': True})
593+
@ddt.ddt
593594
class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
594595
"""
595596
Test Bulk account creation and enrollment from csv file
@@ -641,32 +642,15 @@ def setUp(self):
641642
)
642643

643644
@patch('lms.djangoapps.instructor.views.api.log.info')
644-
def test_account_creation_and_enrollment_with_csv(self, info_log):
645-
"""
646-
Happy path test to create a single new user
647-
"""
648-
csv_content = b"test_student@example.com,test_student_1,tester1,USA"
649-
uploaded_file = SimpleUploadedFile("temp.csv", csv_content)
650-
response = self.client.post(self.url, {'students_list': uploaded_file, 'email-students': True})
651-
assert response.status_code == 200
652-
data = json.loads(response.content.decode('utf-8'))
653-
assert len(data['row_errors']) == 0
654-
assert len(data['warnings']) == 0
655-
assert len(data['general_errors']) == 0
656-
657-
manual_enrollments = ManualEnrollmentAudit.objects.all()
658-
assert manual_enrollments.count() == 1
659-
assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
660-
661-
# test the log for email that's send to new created user.
662-
info_log.assert_called_with('email sent to new created user at %s', 'test_student@example.com')
663-
664-
@patch('lms.djangoapps.instructor.views.api.log.info')
665-
def test_account_creation_and_enrollment_with_csv_with_blank_lines(self, info_log):
645+
@ddt.data(
646+
b"test_student@example.com,test_student_1,tester1,USA", # Typical use case.
647+
b"\ntest_student@example.com,test_student_1,tester1,USA\n\n", # Blank lines.
648+
b"\xef\xbb\xbftest_student@example.com,test_student_1,tester1,USA", # Unicode signature (BOM).
649+
)
650+
def test_account_creation_and_enrollment_with_csv(self, csv_content, info_log):
666651
"""
667652
Happy path test to create a single new user
668653
"""
669-
csv_content = b"\ntest_student@example.com,test_student_1,tester1,USA\n\n"
670654
uploaded_file = SimpleUploadedFile("temp.csv", csv_content)
671655
response = self.client.post(self.url, {'students_list': uploaded_file, 'email-students': True})
672656
assert response.status_code == 200
@@ -4385,7 +4369,7 @@ def call_add_users_to_cohorts(self, csv_data, suffix='.csv'):
43854369
"""
43864370
# this temporary file will be removed in `self.tearDown()`
43874371
__, file_name = tempfile.mkstemp(suffix=suffix, dir=self.tempdir)
4388-
with open(file_name, 'w') as file_pointer:
4372+
with open(file_name, 'w', encoding='utf-8-sig') as file_pointer:
43894373
file_pointer.write(csv_data)
43904374
with open(file_name) as file_pointer:
43914375
url = reverse('add_users_to_cohorts', kwargs={'course_id': str(self.course.id)})

lms/djangoapps/instructor/views/api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def register_and_enroll_students(request, course_id): # pylint: disable=too-man
339339
try:
340340
upload_file = request.FILES.get('students_list')
341341
if upload_file.name.endswith('.csv'):
342-
students = list(csv.reader(upload_file.read().decode('utf-8').splitlines()))
342+
students = list(csv.reader(upload_file.read().decode('utf-8-sig').splitlines()))
343343
course = get_course_by_id(course_id)
344344
else:
345345
general_errors.append({
@@ -1519,7 +1519,7 @@ def _cohorts_csv_validator(file_storage, file_to_validate):
15191519
Verifies that the expected columns are present in the CSV used to add users to cohorts.
15201520
"""
15211521
with file_storage.open(file_to_validate) as f:
1522-
reader = csv.reader(f.read().decode('utf-8').splitlines())
1522+
reader = csv.reader(f.read().decode('utf-8-sig').splitlines())
15231523

15241524
try:
15251525
fieldnames = next(reader)
@@ -3332,7 +3332,7 @@ def build_row_errors(key, _user, row_count):
33323332
try:
33333333
upload_file = request.FILES.get('students_list')
33343334
if upload_file.name.endswith('.csv'):
3335-
students = list(csv.reader(upload_file.read().decode('utf-8').splitlines()))
3335+
students = list(csv.reader(upload_file.read().decode('utf-8-sig').splitlines()))
33363336
else:
33373337
general_errors.append(_('Make sure that the file you upload is in CSV format with no '
33383338
'extraneous characters or rows.'))

0 commit comments

Comments
 (0)