list2form : gestion des erreurs et des petits fichiers (merci cgi.py…) master
authorProgfou <jean-christophe.andre@auf.org>
Thu, 7 Mar 2019 23:06:39 +0000 (18:06 -0500)
committerProgfou <jean-christophe.andre@auf.org>
Thu, 7 Mar 2019 23:06:39 +0000 (18:06 -0500)
wcs/list2form.py

index 806eae4..cbbd3c3 100755 (executable)
@@ -4,10 +4,13 @@
 # Mise en place dans Apache :
 #  ScriptAlias /cgi-bin/list2form.py /usr/local/lib/list2form.py
 import time
+import sys # exit brutal sur erreur
 import os
+import io
 import csv
 import cgi
 import cgitb
+from exceptions import UnicodeDecodeError, UnicodeEncodeError
 cgitb.enable(display=0, logdir="/tmp")
 
 try:
@@ -44,7 +47,8 @@ div { margin-top: 0.5em; }
     <select name="encoding">
       <option value="iso-8859-1">Latin-1 / Europe occidentale (ISO-8859-1, utilisé par GDE)</option>
       <option value="iso-8859-15">Latin-9 / Europe occidentale (ISO-8859-15/EURO)</option>
-      <option value="utf-8">Unicode (UTF-8)</option>
+      <option value="utf-8-sig">Unicode (UTF-8)</option>
+      <option value="utf-16">Unicode (UTF-16)</option>
     </select>
   </div>
   <div>
@@ -71,6 +75,29 @@ div { margin-top: 0.5em; }
 </body>
 </html>""" % today
 
+HTML_ERROR = """<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>Convertisseur de liste vers un formulaire w.c.s</title>
+  <style>
+body { margin: 0; padding: 0; background: #ffffff; }
+div#content { margin: 0; padding: 0.5em; width: 45em; background: #f0f0ff; }
+div { margin-top: 0.5em; }
+  </style>
+</head>
+<body>
+  <div id="content">
+  <h1>Erreur de conversion :</h1>
+  <div>
+    <p>%(message)s</p>
+  </div>
+  <div>
+    <code>%(details)s</code>
+  </div>
+  </div>
+</body>
+</html>"""
+
 WCS_FORM = """<?xml version="1.0" encoding="%(encoding)s"?>
 <formdef>
   <name>%(form_name)s</name>
@@ -119,9 +146,19 @@ def plain2list(fd):
             item_list.append(d)
     return item_list
 
+def utf8_encoder(unicode_stream):
+    for line in unicode_stream:
+        yield line.encode('utf-8')
+
+def unicode_csv_reader(unicode_stream, **kwargs):
+    # csv.py doesn't do Unicode; encode temporarily as UTF-8:
+    for row in csv.reader(utf8_encoder(unicode_stream), **kwargs):
+        # decode UTF-8 back to Unicode, cell by cell:
+        yield [unicode(cell, 'utf-8') for cell in row]
+
 def csv2list(fd):
     item_list = []
-    for l in csv.reader(fd):
+    for l in unicode_csv_reader(fd):
         if not l:
             continue
         d = l[0].strip()
@@ -134,19 +171,39 @@ if form and form['filename'].type in ('text/plain','text/csv'):
     encoding = form.getvalue('encoding')
     delete_first = form.getvalue('delete_first')
     conv_func = form['filename'].type.split('/')[-1] + '2list'
-    item_list = globals()[conv_func](form['filename'].file)
+    # file field is not always a file...
+    if hasattr(form['filename'].file, 'fileno'):
+        item_fd = form['filename'].file.fileno()
+    else:
+        import tempfile
+        tmpfile = tempfile.TemporaryFile('rw+b')
+        tmpfile.write(form['filename'].file.read())
+        tmpfile.seek(0)
+        item_fd = tmpfile.fileno()
+    item_file = io.open(item_fd, 'rt', encoding=encoding)
+    try:
+        item_list = globals()[conv_func](item_file)
+    except (UnicodeDecodeError, UnicodeEncodeError) as e:
+        print "Content-Type: text/html; charset=utf-8\r\n\r\n",
+        print HTML_ERROR % {
+          'message': "Erreur de décodage du fichier. Vérifiez l'encodage choisi pour le fichier.",
+          'details': e,
+        },
+        sys.exit(0)
     if delete_first:
         item_list.pop(0)
     form_name = form.getvalue('form_name').decode('utf-8')
     url_name = simplify(form_name)
     file_name = u'%s.wcs' % url_name
     field_name = form.getvalue('field_name').decode('utf-8')
+    # conversion systématique en UTF-8
+    encoding = 'utf-8'
     info = {
         'encoding': cgi.escape(encoding),
         'form_name': cgi.escape(form_name.encode(encoding)),
         'url_name': cgi.escape(url_name.encode(encoding)),
         'field_name': cgi.escape(field_name.encode(encoding)),
-        'item_list': '\n'.join([WCS_ITEM % cgi.escape(i) for i in item_list]),
+        'item_list': '\n'.join([WCS_ITEM % cgi.escape(i.encode(encoding)) for i in item_list]),
     }
     #print "Location: https://preprod-formulaires.auf.org/admin/forms/import\r\n",
     print "Content-Type: application/x-wcs-form; name=\"%s\"\r\n" % file_name,