Merge pull request #1063 from emanuelschuetze/fix-1023

Improved motion csv import messages (fixes #1023)
This commit is contained in:
Oskar Hahn 2013-11-18 09:11:00 -08:00
commit 962636f84c
4 changed files with 113 additions and 89 deletions

View File

@ -56,13 +56,13 @@ class Assignment(SlideMixin, models.Model):
class Meta:
permissions = (
('can_see_assignment', ugettext_noop('Can see assignments')), # TODO: Add plural s to the codestring
('can_see_assignment', ugettext_noop('Can see elections')), # TODO: Add plural s to the codestring
('can_nominate_other', ugettext_noop('Can nominate another person')),
('can_nominate_self', ugettext_noop('Can nominate oneself')),
('can_manage_assignment', ugettext_noop('Can manage assignments')), # TODO: Add plural s also to the codestring
('can_manage_assignment', ugettext_noop('Can manage elections')), # TODO: Add plural s also to the codestring
)
ordering = ('name',)
verbose_name = ugettext_noop('Assignment')
verbose_name = ugettext_noop('Election')
def __unicode__(self):
return self.name
@ -88,7 +88,7 @@ class Assignment(SlideMixin, models.Model):
raise ValueError(_('%s is not a valid status.') % html_strong(status))
if self.status == status:
raise ValueError(
_('The assignment status is already %s.') % html_strong(status_dict[status]))
_('The election status is already %s.') % html_strong(status_dict[status]))
self.status = status
self.save()

View File

@ -19,7 +19,7 @@
<a href="{{ assignment|absolute_url }}">{{ assignment }}</a>
</li>
{% empty %}
<li>{% trans 'No assignments available.' %}</li>
<li>{% trans 'No elections available.' %}</li>
{% endfor %}
</ul>

View File

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-11-12 10:56+0100\n"
"POT-Creation-Date: 2013-11-16 20:18+0100\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -314,7 +314,7 @@ msgstr ""
#: motion/templates/motion/category_form.html:27
#: motion/templates/motion/motion_form.html:67
#: motion/templates/motion/motion_form_csv_import.html:42
#: motion/templates/motion/poll_form.html:73
#: motion/templates/motion/poll_form.html:74
#: participant/templates/participant/edit.html:56
#: participant/templates/participant/group_edit.html:31
#: participant/templates/participant/import.html:44
@ -415,7 +415,7 @@ msgid "Do you want to save the changed order of agenda items?"
msgstr ""
#: agenda/templates/agenda/overview.html:33
#: agenda/templates/agenda/view.html:86 assignment/models.py:288
#: agenda/templates/agenda/view.html:86 assignment/models.py:289
#: assignment/views.py:565
#: assignment/templates/assignment/assignment_detail.html:210
#: assignment/templates/assignment/assignment_detail.html:214
@ -423,18 +423,18 @@ msgstr ""
#: assignment/templates/assignment/slide.html:72 motion/models.py:699
#: motion/pdf.py:124 motion/pdf.py:269
#: motion/templates/motion/motion_detail.html:215
#: motion/templates/motion/slide.html:21 utils/views.py:333
#: motion/templates/motion/slide.html:23 utils/views.py:333
msgid "Yes"
msgstr ""
#: agenda/templates/agenda/overview.html:34
#: agenda/templates/agenda/view.html:87 assignment/models.py:288
#: agenda/templates/agenda/view.html:87 assignment/models.py:289
#: assignment/views.py:566
#: assignment/templates/assignment/assignment_detail.html:211
#: assignment/templates/assignment/slide.html:69 motion/models.py:699
#: motion/pdf.py:124 motion/pdf.py:270
#: motion/templates/motion/motion_detail.html:216
#: motion/templates/motion/slide.html:22 utils/views.py:333
#: motion/templates/motion/slide.html:24 utils/views.py:333
msgid "No"
msgstr ""
@ -585,7 +585,7 @@ msgstr ""
#: assignment/templates/assignment/assignment_detail.html:113
#: assignment/templates/assignment/poll_view.html:87
#: mediafile/templates/mediafile/pdfs_widget.html:32
#: motion/templates/motion/poll_form.html:70
#: motion/templates/motion/poll_form.html:71
#: projector/templates/projector/overlay_message_widget.html:10
#: templates/formbuttons_saveapply.html:7
msgid "Apply"
@ -670,7 +670,7 @@ msgid "Comment on the ballot paper"
msgstr ""
#: assignment/models.py:59
msgid "Can see assignments"
msgid "Can see elections"
msgstr ""
#: assignment/models.py:60
@ -682,52 +682,61 @@ msgid "Can nominate oneself"
msgstr ""
#: assignment/models.py:62
msgid "Can manage assignments"
msgid "Can manage elections"
msgstr ""
#: assignment/models.py:87
#: assignment/models.py:65 assignment/views.py:497 assignment/views.py:515
#: assignment/templates/assignment/assignment_detail.html:8
#: assignment/templates/assignment/assignment_list.html:33
#: assignment/templates/assignment/poll_view.html:7
#: assignment/templates/assignment/slide.html:18
#: assignment/templates/search/assignment-results.html:7
msgid "Election"
msgstr ""
#: assignment/models.py:88
#, python-format
msgid "%s is not a valid status."
msgstr ""
#: assignment/models.py:90
#: assignment/models.py:91
#, python-format
msgid "The assignment status is already %s."
msgid "The election status is already %s."
msgstr ""
#: assignment/models.py:103
#: assignment/models.py:104
#, python-format
msgid "<b>%s</b> is already a candidate."
msgstr ""
#: assignment/models.py:105 assignment/views.py:157
#: assignment/models.py:106 assignment/views.py:157
msgid "The candidate list is already closed."
msgstr ""
#: assignment/models.py:112
#: assignment/models.py:113
#, python-format
msgid "%s does not want to be a candidate."
msgstr ""
#: assignment/models.py:126
#: assignment/models.py:127
#, python-format
msgid "%s is no candidate"
msgstr ""
#: assignment/models.py:235 assignment/views.py:309
#: assignment/models.py:236 assignment/views.py:309
msgid "Assignment"
msgstr ""
#: assignment/models.py:259
#: assignment/models.py:260
#, python-format
msgid "Ballot %d"
msgstr ""
#: assignment/models.py:288 motion/models.py:699
#: assignment/models.py:289 motion/models.py:699
msgid "Abstain"
msgstr ""
#: assignment/models.py:290 motion/templates/motion/poll_form.html:38
#: assignment/models.py:291 motion/templates/motion/poll_form.html:39
msgid "Votes"
msgstr ""
@ -848,7 +857,7 @@ msgstr ""
msgid "Ballot was successfully deleted."
msgstr ""
#: assignment/views.py:332 assignment/templates/assignment/widget.html:22
#: assignment/views.py:332
msgid "No assignments available."
msgstr ""
@ -897,7 +906,7 @@ msgstr ""
#: assignment/templates/assignment/assignment_detail.html:228
#: assignment/templates/assignment/poll_view.html:55
#: assignment/templates/assignment/slide.html:86
#: motion/templates/motion/poll_form.html:47
#: motion/templates/motion/poll_form.html:48
msgid "Invalid votes"
msgstr ""
@ -908,20 +917,11 @@ msgstr ""
#: assignment/templates/assignment/slide.html:99
#: assignment/templates/assignment/slide.html:104 motion/pdf.py:125
#: motion/templates/motion/motion_detail.html:220
#: motion/templates/motion/poll_form.html:51
#: motion/templates/motion/slide.html:26 poll/models.py:67
#: motion/templates/motion/poll_form.html:52
#: motion/templates/motion/slide.html:28 poll/models.py:67
msgid "Votes cast"
msgstr ""
#: assignment/views.py:497 assignment/views.py:515
#: assignment/templates/assignment/assignment_detail.html:8
#: assignment/templates/assignment/assignment_list.html:33
#: assignment/templates/assignment/poll_view.html:7
#: assignment/templates/assignment/slide.html:18
#: assignment/templates/search/assignment-results.html:7
msgid "Election"
msgstr ""
#: assignment/views.py:522
#, python-format
msgid "%d. ballot"
@ -945,7 +945,7 @@ msgstr[1] ""
#: assignment/templates/assignment/assignment_detail.html:212
#: assignment/templates/assignment/slide.html:70 motion/pdf.py:124
#: motion/pdf.py:271 motion/templates/motion/motion_detail.html:217
#: motion/templates/motion/slide.html:23
#: motion/templates/motion/slide.html:25
msgid "Abstention"
msgstr ""
@ -1040,7 +1040,7 @@ msgstr ""
#: assignment/templates/assignment/assignment_detail.html:233
#: assignment/templates/assignment/slide.html:90 motion/pdf.py:124
#: motion/templates/motion/motion_detail.html:218
#: motion/templates/motion/slide.html:24
#: motion/templates/motion/slide.html:26
msgid "Invalid"
msgstr ""
@ -1053,7 +1053,7 @@ msgstr ""
#: assignment/templates/assignment/slide.html:8
#: motion/templates/motion/motion_detail.html:197
#: motion/templates/motion/motion_list.html:41
#: motion/templates/motion/slide.html:7
#: motion/templates/motion/slide.html:8
msgid "Status"
msgstr ""
@ -1090,33 +1090,37 @@ msgid "Short description (for ballot paper)"
msgstr ""
#: assignment/templates/assignment/poll_view.html:33
#: motion/templates/motion/poll_form.html:30
#: motion/templates/motion/poll_form.html:31
msgid "Special values"
msgstr ""
#: assignment/templates/assignment/poll_view.html:33
#: motion/templates/motion/poll_form.html:30 poll/models.py:225
#: motion/templates/motion/poll_form.html:31 poll/models.py:225
msgid "majority"
msgstr ""
#: assignment/templates/assignment/poll_view.html:33
#: motion/templates/motion/poll_form.html:30 poll/models.py:227
#: motion/templates/motion/poll_form.html:31 poll/models.py:227
#: poll/models.py:229
msgid "undocumented"
msgstr ""
#: assignment/templates/assignment/poll_view.html:78
#: motion/templates/motion/poll_form.html:61
#: motion/templates/motion/poll_form.html:62
msgid "Ballot paper as PDF"
msgstr ""
#: assignment/templates/assignment/poll_view.html:84
#: motion/templates/motion/poll_form.html:67
#: motion/templates/motion/poll_form.html:68
#: projector/templates/projector/select_widgets.html:28
#: templates/formbuttons_save.html:4 templates/formbuttons_saveapply.html:4
msgid "Save"
msgstr ""
#: assignment/templates/assignment/widget.html:22
msgid "No elections available."
msgstr ""
#: config/models.py:21
msgid "Can manage configuration"
msgstr ""
@ -1271,7 +1275,7 @@ msgstr ""
#: motion/templates/motion/motion_detail.html:21
#: motion/templates/motion/motion_diff.html:35
#: motion/templates/motion/motion_diff.html:39
#: motion/templates/motion/slide.html:59
#: motion/templates/motion/slide.html:61
msgid "Version"
msgstr ""
@ -1365,48 +1369,56 @@ msgstr ""
msgid "No PDFs available."
msgstr ""
#: motion/csv_import.py:39 participant/api.py:104
#: motion/csv_import.py:37 participant/api.py:104
msgid "Import file has wrong character encoding, only UTF-8 is supported!"
msgstr ""
#: motion/csv_import.py:57 motion/csv_import.py:70 motion/csv_import.py:108
#: motion/csv_import.py:51
#, python-format
msgid "Line %d of import file:"
msgid "Line %d:"
msgstr ""
#: motion/csv_import.py:58
#: motion/csv_import.py:57
msgid ""
"Line is malformed. Motion not imported. Please check the required values."
msgstr ""
#: motion/csv_import.py:71
#: motion/csv_import.py:69
msgid "Identifier already exists. Motion not imported."
msgstr ""
#: motion/csv_import.py:85
#: motion/csv_import.py:83
msgid "Category unknown. No category is used."
msgstr ""
#: motion/csv_import.py:87
#: motion/csv_import.py:85
msgid "Several suitable categories found. No category is used."
msgstr ""
#: motion/csv_import.py:96
#: motion/csv_import.py:94
msgid "Several suitable submitters found."
msgstr ""
#: motion/csv_import.py:103
#: motion/csv_import.py:101
msgid "Submitter unknown. Default submitter is used."
msgstr ""
#: motion/csv_import.py:117
#: motion/csv_import.py:114
msgid "Motion imported"
msgstr ""
#: motion/csv_import.py:121
msgid "Errors"
msgstr ""
#: motion/csv_import.py:129
msgid "Warnings"
msgstr ""
#: motion/forms.py:37 motion/models.py:539 motion/pdf.py:147
#: motion/templates/motion/motion_detail.html:88
#: motion/templates/motion/motion_diff.html:54
#: motion/templates/motion/slide.html:67
#: motion/templates/motion/slide.html:69
msgid "Reason"
msgstr ""
@ -1417,7 +1429,7 @@ msgstr ""
#: motion/forms.py:75 motion/pdf.py:48
#: motion/templates/motion/motion_detail.html:177
#: motion/templates/motion/motion_list.html:42
#: motion/templates/motion/slide.html:39
#: motion/templates/motion/slide.html:41
msgid "Submitter"
msgstr ""
@ -1437,7 +1449,7 @@ msgstr ""
#: motion/forms.py:119 motion/templates/motion/motion_detail.html:242
#: motion/templates/motion/motion_list.html:40
#: motion/templates/motion/slide.html:48
#: motion/templates/motion/slide.html:50
msgid "Category"
msgstr ""
@ -1506,9 +1518,9 @@ msgstr ""
#: motion/templates/motion/motion_detail.html:19
#: motion/templates/motion/motion_diff.html:6
#: motion/templates/motion/motion_diff.html:19
#: motion/templates/motion/poll_form.html:6
#: motion/templates/motion/poll_form.html:14
#: motion/templates/motion/slide.html:58
#: motion/templates/motion/poll_form.html:7
#: motion/templates/motion/poll_form.html:15
#: motion/templates/motion/slide.html:60
#: motion/templates/search/motion-results.html:7
msgid "Motion"
msgstr ""
@ -1861,7 +1873,7 @@ msgstr ""
#: motion/templates/motion/motion_detail.html:32
#: motion/templates/motion/motion_list.html:78
#: motion/templates/motion/poll_form.html:21
#: motion/templates/motion/poll_form.html:22
msgid "Show motion"
msgstr ""
@ -1988,7 +2000,7 @@ msgstr ""
#: motion/templates/motion/motion_diff.html:27
#: motion/templates/motion/motion_form.html:56
#: motion/templates/motion/poll_form.html:18
#: motion/templates/motion/poll_form.html:19
msgid "Back to motion"
msgstr ""
@ -2073,15 +2085,15 @@ msgstr ""
msgid "Needs supporters"
msgstr ""
#: motion/templates/motion/poll_form.html:37
#: motion/templates/motion/poll_form.html:38
msgid "Option"
msgstr ""
#: motion/templates/motion/slide.html:13
#: motion/templates/motion/slide.html:19
msgid "Poll result"
msgstr ""
#: motion/templates/motion/slide.html:31
#: motion/templates/motion/slide.html:33
msgid "No poll results available."
msgstr ""

View File

@ -27,8 +27,6 @@ def import_motions(csv_file, default_submitter, override=False, importing_person
when the flag 'override' is true. If no or multiple categories found,
the category is set to None.
"""
error_messages = []
warning_messages = []
count_success = 0
count_lines = 0
@ -43,20 +41,21 @@ def import_motions(csv_file, default_submitter, override=False, importing_person
dialect = csv.Sniffer().sniff(csv_file.readline())
dialect = csv_ext.patchup(dialect)
csv_file.seek(0)
all_error_messages = []
all_warning_messages = []
for (line_no, line) in enumerate(csv.reader(csv_file, dialect=dialect)):
warnings = []
warning = []
if line_no < 1:
# Do not read the header line
continue
importline = html_strong(_('Line %d:') % (line_no + 1))
count_lines += 1
# Check format
try:
(identifier, title, text, reason, submitter, category) = line[:6]
except ValueError:
error_line = html_strong(_('Line %d of import file:') % (line_no + 1))
msg = _('Line is malformed. Motion not imported. Please check the required values.')
error_messages.append("%s<br>%s" % (error_line, msg))
all_error_messages.append("%s %s" % (importline, msg))
continue
# Check existing motions according to the identifier
@ -67,9 +66,8 @@ def import_motions(csv_file, default_submitter, override=False, importing_person
motion = Motion(identifier=identifier)
else:
if not override:
error_line = html_strong(_('Line %d of import file:') % (line_no + 1))
msg = _('Identifier already exists. Motion not imported.')
error_messages.append("%s<br>%s" % (error_line, msg))
all_error_messages.append("%s %s" % (importline, msg))
continue
else:
motion = Motion()
@ -82,9 +80,9 @@ def import_motions(csv_file, default_submitter, override=False, importing_person
try:
motion.category = Category.objects.get(name=category)
except Category.DoesNotExist:
warnings.append(_('Category unknown. No category is used.'))
warning.append(_('Category unknown. No category is used.'))
except Category.MultipleObjectsReturned:
warnings.append(_('Several suitable categories found. No category is used.'))
warning.append(_('Several suitable categories found. No category is used.'))
motion.save()
# Add submitter
@ -93,24 +91,22 @@ def import_motions(csv_file, default_submitter, override=False, importing_person
for person in Persons():
if person.clean_name == submitter.decode('utf8'):
if person_found:
warnings.append(_('Several suitable submitters found.'))
warning.append(_('Several suitable submitters found.'))
person_found = False
break
else:
new_submitter = person
person_found = True
if not person_found:
warnings.append(_('Submitter unknown. Default submitter is used.'))
warning.append(_('Submitter unknown. Default submitter is used.'))
new_submitter = default_submitter
# show summarized warning message for each import line
if warnings:
warning_line = _('Line %d of import file:') % (line_no + 1)
warning_message_string = "%s<ul>" % html_strong(warning_line)
for w in warnings:
warning_message_string += "<li>%s</li>" % w
warning_message_string += "</ul>"
warning_messages.append(warning_message_string)
# add all warnings of each csv line to one warning message
if warning:
warning_message_string = "%s " % importline
warning_message_string += " ".join(warning)
all_warning_messages.append(warning_message_string)
motion.clear_submitters()
motion.add_submitter(new_submitter)
@ -118,4 +114,20 @@ def import_motions(csv_file, default_submitter, override=False, importing_person
person=importing_person)
count_success += 1
return (count_success, count_lines, error_messages, warning_messages)
# Build final error message with all error items (one bullet point for each csv line)
full_error_message = None
if all_error_messages:
full_error_message = "%s <ul>" % html_strong(_("Errors"))
for error in all_error_messages:
full_error_message += "<li>%s</li>" % error
full_error_message += "</ul>"
# Build final warning message with all warning items (one bullet point for each csv line)
full_warning_message = None
if all_warning_messages:
full_warning_message = "%s <ul>" % html_strong(_("Warnings"))
for warning in all_warning_messages:
full_warning_message += "<li>%s</li>" % warning
full_warning_message += "</ul>"
return (count_success, count_lines, [full_error_message], [full_warning_message])