Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force translations in bulk export/import of user data #9557

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions kolibri/core/auth/management/commands/bulkexportusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,14 @@ def kind_of_roles(field, obj):
}


map_output = partial(output_mapper, labels=labels, output_mappings=output_mappings)
def map_output(item):
return partial(
output_mapper, labels=translate_labels(), output_mappings=output_mappings
)(item)


def translate_labels():
global labels
labels = OrderedDict(
return OrderedDict(
(
("id", _("Database ID ({})").format("UUID")),
("username", _("Username ({})").format("USERNAME")),
Expand Down Expand Up @@ -152,7 +154,7 @@ def csv_file_generator(facility, filepath, overwrite=True):
raise ValueError("{} already exists".format(filepath))
queryset = FacilityUser.objects.filter(facility=facility)

header_labels = labels.values()
header_labels = translate_labels().values()

csv_file = open_csv_for_writing(filepath)

Expand Down Expand Up @@ -257,7 +259,6 @@ def handle_async(self, *args, **options):
# set language for the translation of the messages
locale = settings.LANGUAGE_CODE if not options["locale"] else options["locale"]
translation.activate(locale)
translate_labels()

self.overall_error = []
filepath = self.get_filepath(options)
Expand Down
30 changes: 17 additions & 13 deletions kolibri/core/auth/management/commands/bulkimportusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,11 @@ def csv_values_validation(self, reader, header_translation):
validator.roles,
)

def append_error(self, msg):
# force translation to str type, to be serialized into json:
translation.activate(self.locale)
self.overall_error.append(str(msg))

def csv_headers_validation(self, filepath):
csv_file = open_csv_for_reading(filepath)
with csv_file as f:
Expand All @@ -482,10 +487,10 @@ def csv_headers_validation(self, filepath):
# If any col is missing from the header, it's an error
for col in fieldnames:
if col not in neutral_header:
self.overall_error.append(MESSAGES[REQUIRED_COLUMN].format(col))
self.append_error(MESSAGES[REQUIRED_COLUMN].format(col))

elif any(col in fieldnames for col in neutral_header):
self.overall_error.append(MESSAGES[INVALID_HEADER])
self.append_error(MESSAGES[INVALID_HEADER])

return has_header

Expand Down Expand Up @@ -676,7 +681,7 @@ def get_facility(self, options):
else:
default_facility = Facility.get_default_facility()
if not default_facility:
self.overall_error.append(MESSAGES[NO_FACILITY])
self.append_error(MESSAGES[NO_FACILITY])
raise CommandError(self.overall_error[-1])

return default_facility
Expand All @@ -687,7 +692,7 @@ def get_number_lines(self, filepath):
number_lines = len(f.readlines())
except (ValueError, FileNotFoundError, csv.Error) as e:
number_lines = None
self.overall_error.append(MESSAGES[FILE_READ_ERROR].format(e))
self.append_error(MESSAGES[FILE_READ_ERROR].format(e))
return number_lines

def get_delete(self, options, keeping_users, update_classes):
Expand Down Expand Up @@ -761,16 +766,14 @@ def exit_if_error(self):
if self.overall_error:
classes_report = {"created": 0, "updated": 0, "cleared": 0}
users_report = {"created": 0, "updated": 0, "deleted": 0}
# force translation to str type, to be serialized into json:
overall_error = [str(msg) for msg in self.overall_error]
if self.job:
self.job.extra_metadata["overall_error"] = overall_error
self.job.extra_metadata["overall_error"] = self.overall_error
self.job.extra_metadata["per_line_errors"] = 0
self.job.extra_metadata["classes"] = classes_report
self.job.extra_metadata["users"] = users_report
self.job.extra_metadata["filename"] = ""
self.job.save_meta()
raise CommandError("File errors: {}".format(overall_error))
raise CommandError("File errors: {}".format(self.overall_error))
return

def remove_memberships(self, users, enrolled, assigned):
Expand Down Expand Up @@ -807,7 +810,6 @@ def output_messages(
# freeze message translations:
for line in per_line_errors:
line["message"] = str(line["message"])
self.overall_error = [str(msg) for msg in self.overall_error]

if self.job:
self.job.extra_metadata["overall_error"] = self.overall_error
Expand Down Expand Up @@ -838,8 +840,10 @@ def handle_async(self, *args, **options):
per_line_errors = []

# set language for the translation of the messages
locale = settings.LANGUAGE_CODE if not options["locale"] else options["locale"]
translation.activate(locale)
self.locale = (
settings.LANGUAGE_CODE if not options["locale"] else options["locale"]
)
translation.activate(self.locale)

self.job = get_current_job()
filepath = options["filepath"]
Expand All @@ -851,7 +855,7 @@ def handle_async(self, *args, **options):
# validate csv headers:
has_header = self.csv_headers_validation(filepath)
if not has_header:
self.overall_error.append(MESSAGES[INVALID_HEADER])
self.append_error(MESSAGES[INVALID_HEADER])
self.exit_if_error()
self.progress_update(1) # state=csv_headers
try:
Expand All @@ -862,7 +866,7 @@ def handle_async(self, *args, **options):
reader, self.header_translation
)
except (ValueError, FileNotFoundError, csv.Error) as e:
self.overall_error.append(MESSAGES[FILE_READ_ERROR].format(e))
self.append_error(MESSAGES[FILE_READ_ERROR].format(e))
self.exit_if_error()
(
db_new_users,
Expand Down