Commit 17b16b11 by Ned Batchelder

Ensure correct CSV headers for non-English

If we pass non-ASCII strings to create_csv_response, it will call
unicode() on it, and fail with UnicodeDecodeError.  So pass Unicode
strings, or ASCII-only bytestrings for the headers.
parent 1bd2ec25
...@@ -470,7 +470,7 @@ def get_students_opened_subsection(request, csv=False): ...@@ -470,7 +470,7 @@ def get_students_opened_subsection(request, csv=False):
# Subsection name is everything after 3rd space in tooltip # Subsection name is everything after 3rd space in tooltip
filename = sanitize_filename(' '.join(tooltip.split(' ')[3:])) filename = sanitize_filename(' '.join(tooltip.split(' ')[3:]))
header = [_("Name").encode('utf-8'), _("Username").encode('utf-8')] header = [_("Name"), _("Username")]
for student in students: for student in students:
results.append([student['student__profile__name'], student['student__username']]) results.append([student['student__profile__name'], student['student__username']])
...@@ -528,9 +528,8 @@ def get_students_problem_grades(request, csv=False): ...@@ -528,9 +528,8 @@ def get_students_problem_grades(request, csv=False):
tooltip = request.GET.get('tooltip') tooltip = request.GET.get('tooltip')
filename = sanitize_filename(tooltip[:tooltip.rfind(' - ')]) filename = sanitize_filename(tooltip[:tooltip.rfind(' - ')])
header = [_("Name").encode('utf-8'), _("Username").encode('utf-8'), _("Grade").encode('utf-8'), _("Percent").encode('utf-8')] header = [_("Name"), _("Username"), _("Grade"), _("Percent")]
for student in students: for student in students:
percent = 0 percent = 0
if student['max_grade'] > 0: if student['max_grade'] > 0:
percent = round(student['grade'] * 100 / student['max_grade']) percent = round(student['grade'] * 100 / student['max_grade'])
...@@ -556,10 +555,13 @@ def post_metrics_data_csv(request): ...@@ -556,10 +555,13 @@ def post_metrics_data_csv(request):
results = [] results = []
if data_type == 'subsection': if data_type == 'subsection':
header = [_("Section").encode('utf-8'), _("Subsection").encode('utf-8'), _("Opened by this number of students").encode('utf-8')] header = [_("Section"), _("Subsection"), _("Opened by this number of students")]
filename = sanitize_filename(_('subsections') + '_' + course_id) filename = sanitize_filename(_('subsections') + '_' + course_id)
elif data_type == 'problem': elif data_type == 'problem':
header = [_("Section").encode('utf-8'), _("Problem").encode('utf-8'), _("Name").encode('utf-8'), _("Count of Students").encode('utf-8'), _("Percent of Students").encode('utf-8'), _("Score").encode('utf-8')] header = [
_("Section"), _("Problem"), _("Name"), _("Count of Students"),
_("Percent of Students"), _("Score"),
]
filename = sanitize_filename(_('problems') + '_' + course_id) filename = sanitize_filename(_('problems') + '_' + course_id)
for index, section in enumerate(sections): for index, section in enumerate(sections):
......
...@@ -1112,7 +1112,7 @@ def get_sale_order_records(request, course_id): # pylint: disable=unused-argume ...@@ -1112,7 +1112,7 @@ def get_sale_order_records(request, course_id): # pylint: disable=unused-argume
db_columns = [x[0] for x in query_features] db_columns = [x[0] for x in query_features]
csv_columns = [x[1] for x in query_features] csv_columns = [x[1] for x in query_features]
sale_data = instructor_analytics.basic.sale_order_record_features(course_id, db_columns) sale_data = instructor_analytics.basic.sale_order_record_features(course_id, db_columns)
header, datarows = instructor_analytics.csvs.format_dictlist(sale_data, db_columns) # pylint: disable=unused-variable __, datarows = instructor_analytics.csvs.format_dictlist(sale_data, db_columns)
return instructor_analytics.csvs.create_csv_response("e-commerce_sale_order_records.csv", csv_columns, datarows) return instructor_analytics.csvs.create_csv_response("e-commerce_sale_order_records.csv", csv_columns, datarows)
......
...@@ -14,10 +14,13 @@ def create_csv_response(filename, header, datarows): ...@@ -14,10 +14,13 @@ def create_csv_response(filename, header, datarows):
header e.g. ['Name', 'Email'] header e.g. ['Name', 'Email']
datarows e.g. [['Jim', 'jim@edy.org'], ['Jake', 'jake@edy.org'], ...] datarows e.g. [['Jim', 'jim@edy.org'], ['Jake', 'jake@edy.org'], ...]
The data in `header` and `datarows` must be either Unicode strings,
or ASCII-only bytestrings.
""" """
response = HttpResponse(content_type='text/csv') response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename={0}'\ response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)
.format(filename)
csvwriter = csv.writer( csvwriter = csv.writer(
response, response,
dialect='excel', dialect='excel',
...@@ -30,6 +33,7 @@ def create_csv_response(filename, header, datarows): ...@@ -30,6 +33,7 @@ def create_csv_response(filename, header, datarows):
for datarow in datarows: for datarow in datarows:
encoded_row = [unicode(s).encode('utf-8') for s in datarow] encoded_row = [unicode(s).encode('utf-8') for s in datarow]
csvwriter.writerow(encoded_row) csvwriter.writerow(encoded_row)
return response return response
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment