list2form : gestion des erreurs et des petits fichiers (merci cgi.py…)
[progfou.git] / wcs / list2form.py
CommitLineData
4ae2d14d 1#!/usr/bin/python
252760d2 2# -*- coding: utf-8 -*-
5602202b
P
3# Debian-Depends: wcs
4# Mise en place dans Apache :
5# ScriptAlias /cgi-bin/list2form.py /usr/local/lib/list2form.py
4ae2d14d 6import time
1f9d3cc1 7import sys # exit brutal sur erreur
252760d2 8import os
1f9d3cc1 9import io
252760d2
P
10import csv
11import cgi
12import cgitb
1f9d3cc1 13from exceptions import UnicodeDecodeError, UnicodeEncodeError
252760d2
P
14cgitb.enable(display=0, logdir="/tmp")
15
16try:
5602202b 17 from wcs.qommon.misc import simplify
252760d2
P
18except:
19 simplify = lambda s: 'url-name'
20
4ae2d14d
P
21today = time.strftime('%Y-%m-%d')
22
252760d2
P
23HTML_FORM = """<html>
24<head>
25 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
26 <title>Convertisseur de liste vers un formulaire w.c.s</title>
4ae2d14d
P
27 <style>
28body { margin: 0; padding: 0; background: #ffffff; }
29div#content { margin: 0; padding: 0.5em; width: 45em; background: #f0f0ff; }
30form { margin: 1px; }
31fieldset { margin-bottom: 1em; }
32div { margin-top: 0.5em; }
33 </style>
252760d2
P
34</head>
35<body>
4ae2d14d 36 <div id="content">
252760d2 37 <h1>Convertisseur de liste vers un formulaire w.c.s</h1>
4ae2d14d
P
38 <form action="%%(SCRIPT_NAME)s" method="POST" enctype="multipart/form-data">
39 <fieldset>
40 <legend>Source (fichier texte ou CSV à une colonne)</legend>
41 <div>
42 <label>Fichier &agrave; convertir&nbsp;:</label>
43 <input type="file" name="filename" required autofocus />
44 </div>
45 <div>
46 <label>Encodage du fichier &agrave; convertir&nbsp;:</label>
47 <select name="encoding">
48 <option value="iso-8859-1">Latin-1 / Europe occidentale (ISO-8859-1, utilisé par GDE)</option>
49 <option value="iso-8859-15">Latin-9 / Europe occidentale (ISO-8859-15/EURO)</option>
1f9d3cc1
P
50 <option value="utf-8-sig">Unicode (UTF-8)</option>
51 <option value="utf-16">Unicode (UTF-16)</option>
4ae2d14d
P
52 </select>
53 </div>
54 <div>
55 <label>Supprimer la premi&egrave;re ligne du fichier&nbsp;:</label>
fc6b3d17 56 <input type="checkbox" name="delete_first" />
4ae2d14d
P
57 </div>
58 </fieldset>
59 <fieldset>
60 <legend>Destination (formulaire WCS à importer)</legend>
61 <div>
62 <label>Titre du formulaire&nbsp;:</label>
63 <input type="text" name="form_name" size="50" value="Établissements membres TOUS/DRxxx %s" required />
64 </div>
65 <div>
66 <label>Nom du champ liste&nbsp;:</label>
67 <input type="text" name="field_name" size="50" value="Établissement (membre de l'AUF) :" required />
68 </div>
69 </fieldset>
70 <div style="text-align: right;">
71 <input name="convert" type="submit" value="Convertir" />
72 </div>
252760d2 73 </form>
4ae2d14d 74 </div>
252760d2 75</body>
4ae2d14d 76</html>""" % today
252760d2 77
1f9d3cc1
P
78HTML_ERROR = """<html>
79<head>
80 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
81 <title>Convertisseur de liste vers un formulaire w.c.s</title>
82 <style>
83body { margin: 0; padding: 0; background: #ffffff; }
84div#content { margin: 0; padding: 0.5em; width: 45em; background: #f0f0ff; }
85div { margin-top: 0.5em; }
86 </style>
87</head>
88<body>
89 <div id="content">
90 <h1>Erreur de conversion :</h1>
91 <div>
92 <p>%(message)s</p>
93 </div>
94 <div>
95 <code>%(details)s</code>
96 </div>
97 </div>
98</body>
99</html>"""
100
4ae2d14d 101WCS_FORM = """<?xml version="1.0" encoding="%(encoding)s"?>
252760d2
P
102<formdef>
103 <name>%(form_name)s</name>
104 <url_name>%(url_name)s</url_name>
fc6b3d17
P
105 <category category_id="1">Pour importation</category>
106 <workflow workflow_id="_default">Par d&#233;faut</workflow>
107 <detailed_emails>true</detailed_emails>
108 <disabled>false</disabled>
252760d2
P
109 <only_allow_one>true</only_allow_one>
110 <allow_drafts>false</allow_drafts>
111 <discussion>false</discussion>
fc6b3d17
P
112 <enable_tracking_codes>false</enable_tracking_codes>
113 <always_advertise>false</always_advertise>
114 <private_status_and_history>true</private_status_and_history>
252760d2
P
115 <confirmation>true</confirmation>
116 <signing>false</signing>
fc6b3d17 117 <max_field_id>1</max_field_id>
252760d2
P
118 <fields>
119 <field>
120 <label>%(field_name)s</label>
121 <type>item</type>
122 <required>True</required>
123 <hint>Veuillez faire un choix dans la liste...</hint>
124 <in_listing>True</in_listing>
125 <prefill>
126 <type>none</type>
4ae2d14d
P
127 </prefill>
128 <wsf_prefill_explicit>False</wsf_prefill_explicit>
252760d2
P
129 <items>
130%(item_list)s
4ae2d14d
P
131 </items>
132 <show_as_radio>False</show_as_radio>
fc6b3d17 133 <id>0</id>
252760d2
P
134 </field>
135 </fields>
fc6b3d17 136 <options />
252760d2
P
137</formdef>"""
138
139WCS_ITEM = """ <item>%s</item>"""
140
141def plain2list(fd):
142 item_list = []
143 for l in fd.readlines():
e4fdfe59
P
144 d = l.strip()
145 if d != '':
146 item_list.append(d)
252760d2
P
147 return item_list
148
1f9d3cc1
P
149def utf8_encoder(unicode_stream):
150 for line in unicode_stream:
151 yield line.encode('utf-8')
152
153def unicode_csv_reader(unicode_stream, **kwargs):
154 # csv.py doesn't do Unicode; encode temporarily as UTF-8:
155 for row in csv.reader(utf8_encoder(unicode_stream), **kwargs):
156 # decode UTF-8 back to Unicode, cell by cell:
157 yield [unicode(cell, 'utf-8') for cell in row]
158
252760d2
P
159def csv2list(fd):
160 item_list = []
1f9d3cc1 161 for l in unicode_csv_reader(fd):
e5a1703d
P
162 if not l:
163 continue
e4fdfe59
P
164 d = l[0].strip()
165 if d != '':
166 item_list.append(d)
252760d2
P
167 return item_list
168
169form = cgi.FieldStorage()
170if form and form['filename'].type in ('text/plain','text/csv'):
4ae2d14d 171 encoding = form.getvalue('encoding')
252760d2
P
172 delete_first = form.getvalue('delete_first')
173 conv_func = form['filename'].type.split('/')[-1] + '2list'
1f9d3cc1
P
174 # file field is not always a file...
175 if hasattr(form['filename'].file, 'fileno'):
176 item_fd = form['filename'].file.fileno()
177 else:
178 import tempfile
179 tmpfile = tempfile.TemporaryFile('rw+b')
180 tmpfile.write(form['filename'].file.read())
181 tmpfile.seek(0)
182 item_fd = tmpfile.fileno()
183 item_file = io.open(item_fd, 'rt', encoding=encoding)
184 try:
185 item_list = globals()[conv_func](item_file)
186 except (UnicodeDecodeError, UnicodeEncodeError) as e:
187 print "Content-Type: text/html; charset=utf-8\r\n\r\n",
188 print HTML_ERROR % {
189 'message': "Erreur de décodage du fichier. Vérifiez l'encodage choisi pour le fichier.",
190 'details': e,
191 },
192 sys.exit(0)
252760d2
P
193 if delete_first:
194 item_list.pop(0)
4ae2d14d 195 form_name = form.getvalue('form_name').decode('utf-8')
252760d2 196 url_name = simplify(form_name)
4ae2d14d
P
197 file_name = u'%s.wcs' % url_name
198 field_name = form.getvalue('field_name').decode('utf-8')
1f9d3cc1
P
199 # conversion systématique en UTF-8
200 encoding = 'utf-8'
252760d2 201 info = {
4ae2d14d
P
202 'encoding': cgi.escape(encoding),
203 'form_name': cgi.escape(form_name.encode(encoding)),
204 'url_name': cgi.escape(url_name.encode(encoding)),
205 'field_name': cgi.escape(field_name.encode(encoding)),
1f9d3cc1 206 'item_list': '\n'.join([WCS_ITEM % cgi.escape(i.encode(encoding)) for i in item_list]),
252760d2
P
207 }
208 #print "Location: https://preprod-formulaires.auf.org/admin/forms/import\r\n",
209 print "Content-Type: application/x-wcs-form; name=\"%s\"\r\n" % file_name,
210 print "Content-Disposition: attachment; filename=\"%s\"\r\n\r\n" % file_name,
211 print WCS_FORM % info,
212else:
213 print "Content-Type: text/html; charset=utf-8\r\n\r\n",
214 print HTML_FORM % os.environ,
215