From 5d620ba5961cce0ed61c1e056e637950a17bbca4 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Wed, 21 Sep 2022 16:10:04 +0200 Subject: [PATCH] manager: report errors in CSV import using event indexes (#66184) --- chrono/manager/forms.py | 21 +++++++++++++++------ tests/manager/test_event.py | 9 ++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py index dfb79a87..dbb8398d 100644 --- a/chrono/manager/forms.py +++ b/chrono/manager/forms.py @@ -27,6 +27,7 @@ from dateutil.relativedelta import relativedelta from django import forms from django.conf import settings from django.contrib.auth.models import Group +from django.contrib.humanize.templatetags.humanize import ordinal from django.core.exceptions import FieldDoesNotExist from django.core.validators import URLValidator from django.db import transaction @@ -35,6 +36,7 @@ from django.forms import ValidationError, formset_factory from django.template import Context, Template, TemplateSyntaxError, VariableDoesNotExist from django.utils.encoding import force_str from django.utils.formats import date_format +from django.utils.html import format_html, mark_safe from django.utils.timezone import localtime, make_aware, now from django.utils.translation import gettext_lazy as _ @@ -1060,6 +1062,11 @@ class ImportEventsForm(forms.Form): super().__init__(**kwargs) def clean_events_csv_file(self): + class ValidationErrorWithOrdinal(ValidationError): + def __init__(self, message, event_no): + super().__init__(message) + self.message = format_html(message, event_no=mark_safe(ordinal(event_no + 1))) + content = self.cleaned_data['events_csv_file'].read() if b'\0' in content: raise ValidationError(_('Invalid file format.')) @@ -1092,7 +1099,7 @@ class ImportEventsForm(forms.Form): if not csvline: continue if len(csvline) < 3: - raise ValidationError(_('Invalid file format. (line %d)') % (i + 1)) + raise ValidationErrorWithOrdinal(_('Invalid file format. ({event_no} event)'), i) if i == 0 and csvline[0].strip('#') in ('date', 'Date', _('date'), _('Date')): continue @@ -1146,17 +1153,19 @@ class ImportEventsForm(forms.Form): event.start_datetime = event_datetime break else: - raise ValidationError(_('Invalid file format. (date/time format, line %d)') % (i + 1)) + raise ValidationErrorWithOrdinal( + _('Invalid file format. (date/time format, {event_no} event)'), i + ) try: event.places = int(csvline[2]) except ValueError: - raise ValidationError(_('Invalid file format. (number of places, line %d)') % (i + 1)) + raise ValidationError(_('Invalid file format. (number of places, {event_no} event)'), i) if len(csvline) >= 4: try: event.waiting_list_places = int(csvline[3]) except ValueError: raise ValidationError( - _('Invalid file format. (number of places in waiting list, line %d)') % (i + 1) + _('Invalid file format. (number of places in waiting list, {event_no} event)'), i ) column_index = 7 @@ -1183,13 +1192,13 @@ class ImportEventsForm(forms.Form): except ValueError: continue else: - raise ValidationError(_('Invalid file format. (date/time format, line %d)') % (i + 1)) + raise ValidationError(_('Invalid file format. (date/time format, {event_no} event)'), i) if len(csvline) >= 11 and csvline[10]: # duration is optional try: event.duration = int(csvline[10]) except ValueError: - raise ValidationError(_('Invalid file format. (duration, line %d)') % (i + 1)) + raise ValidationError(_('Invalid file format. (duration, {event_no} event)'), i) try: event.full_clean(exclude=['desk', 'meeting_type', 'primary_event']) diff --git a/tests/manager/test_event.py b/tests/manager/test_event.py index 3b5602c0..c3f0480b 100644 --- a/tests/manager/test_event.py +++ b/tests/manager/test_event.py @@ -6,6 +6,7 @@ import pytest import requests from django.core.management import call_command from django.db import connection +from django.test import override_settings from django.test.utils import CaptureQueriesContext from django.utils.timezone import localtime, make_aware, now from webtest import Upload @@ -784,7 +785,13 @@ def test_import_events(app, admin_user): resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00,10', 'text/csv') resp = resp.form.submit(status=200) - assert 'Invalid file format. (date/time format' in resp.text + assert 'Invalid file format. (date/time format, 1st event)' in resp.text + + with override_settings(LANGUAGE_CODE='fr-fr'): + resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00,10', 'text/csv') + resp = resp.form.submit(status=200) + # ensure tag is not escaped + assert '1er' in resp.text resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,blah', 'text/csv') resp = resp.form.submit(status=200) -- 2.35.1