Commit | Line | Data |
---|---|---|
20ae1ad6 P |
1 | #!/usr/bin/python |
2 | # -*- coding: utf-8 -*- | |
3 | """ | |
4 | Outil d'export dynamique de données w.c.s. | |
5 | ||
6 | Copyright : Agence universitaire de la Francophonie — www.auf.org | |
7 | Licence : GNU General Public Licence, version 2 | |
8 | Auteur : Jean Christophe André | |
9 | Date de création : 13 mars 2013 | |
10 | ||
11 | Depends: wcs, python-simplejson, python-magic | |
12 | ||
13 | URL d'accès : | |
14 | - /dynexport => liste des formulaires pour le domaine courant | |
15 | - /dynexport/domains.json => liste des domaines disponibles | |
16 | - /dynexport/formulaire => liste des options ci-dessous | |
17 | - /dynexport/formulaire/fields.json | |
18 | - /dynexport/formulaire/field-names.json | |
19 | - /dynexport/formulaire/field-names.txt | |
20 | - /dynexport/formulaire/data.json | |
21 | - /dynexport/formulaire/last-run.log | |
22 | - /dynexport/formulaire/liste-dossiers.json | |
23 | - /dynexport/formulaire/clear-cache => vide le cache | |
24 | - /dynexport/formulaire/data/nom-dossier.json | |
25 | - /dynexport/formulaire/data/nom-dossier_attachement-1.xxx | |
26 | - /dynexport/formulaire/data/nom-dossier_attachement-2.xxx | |
27 | - /dynexport/formulaire/data/nom-dossier_attachement-… | |
28 | """ | |
29 | import sys | |
30 | import os | |
31 | import os.path | |
32 | import logging | |
33 | import time # time, gmtime, strftime, strptime, struct_time | |
34 | import simplejson as json | |
35 | import magic | |
36 | import mimetypes | |
37 | import unicodedata | |
38 | from cStringIO import StringIO | |
39 | from gzip import GzipFile | |
40 | from re import match | |
41 | ||
42 | DELAIS = 5 # maximum 5 secondes en cache | |
43 | TIME_FORMAT = '%a, %d %b %Y %H:%M:%S GMT' # format date pour HTTP | |
44 | ||
45 | WCS_ROOT_DIR = '/var/lib/wcs' | |
46 | WCS_DOMAIN_SUFFIX = '.auf.org' | |
47 | WCS_FORM_PREFIX = 'form-' | |
48 | WCS_CACHE_DIR = '/var/tmp' | |
49 | ||
50 | #-------------------------------------------------------------------------- | |
51 | # fonctions de traitement | |
52 | #-------------------------------------------------------------------------- | |
53 | ||
54 | def http_redirect(location, code='302'): | |
55 | headers = {} | |
56 | headers['Content-Type'] = 'text/plain; charset=utf-8' | |
57 | headers['Status'] = '302 Redirection' | |
58 | headers['Location'] = location | |
59 | data = """If you see this, it means the automatic redirection has failed. | |
60 | Please go to ${location}""" | |
61 | # envoi de la réponse | |
62 | headers = ''.join(map(lambda x: "%s: %s\r\n" % (x, headers[x]), headers)) | |
63 | f = open('/dev/stdout', 'wb') | |
64 | f.write(headers + "\r\n") | |
65 | if data: | |
66 | f.write(data) | |
67 | f.flush() | |
68 | # arrêt du traitement | |
69 | sys.exit(0) | |
70 | ||
71 | def http_reply_and_exit(data, mime_type='text/html', charset='utf-8'): | |
72 | # références horaires | |
73 | current_time = time.time() | |
74 | mtime = time.gmtime(current_time) | |
75 | etime = time.gmtime(current_time + DELAIS) | |
76 | if os.environ.has_key('HTTP_IF_MODIFIED_SINCE'): | |
77 | try: | |
78 | itime = time.strptime(os.environ['HTTP_IF_MODIFIED_SINCE'], TIME_FORMAT) | |
79 | except ValueError: | |
80 | itime = None | |
81 | else: | |
82 | itime = None | |
83 | # préparation des en-têtes et données | |
84 | headers = {} | |
85 | headers['Content-Type'] = '%s; charset=%s' % (mime_type, charset) | |
86 | headers['Last-Modified'] = time.strftime(TIME_FORMAT, mtime) | |
87 | headers['Expires'] = time.strftime(TIME_FORMAT, etime) | |
88 | if os.environ['REQUEST_METHOD'] == 'GET' and (not itime or mtime > itime): | |
89 | # détermination de la version demandée (compressée ou non) | |
90 | if os.environ.get('HTTP_ACCEPT_ENCODING','').split(',').count('gzip') > 0: | |
91 | zdata = StringIO() | |
92 | GzipFile('', 'w', 9, zdata).write(data) | |
93 | data = zdata.getvalue() | |
94 | headers['Content-Encoding'] = 'gzip' | |
95 | headers['Vary'] = 'Content-Encoding' | |
96 | headers['Content-Length'] = len(data) | |
97 | else: | |
98 | data = None | |
99 | # envoi de la réponse | |
100 | headers = ''.join(map(lambda x: "%s: %s\r\n" % (x, headers[x]), headers)) | |
101 | f = open('/dev/stdout', 'wb') | |
102 | f.write(headers + "\r\n") | |
103 | if data: | |
104 | f.write(data) | |
105 | f.flush() | |
106 | # arrêt du traitement | |
107 | sys.exit(0) | |
108 | ||
109 | ||
110 | def _reduce_to_alnum(s, replacement_char='-'): | |
111 | """réduction d'une chaîne de caractères à de l'alpha-numérique""" | |
112 | ||
113 | if type(s) is not unicode: | |
114 | s = unicode(s, 'utf-8') | |
115 | s = unicodedata.normalize('NFKD', s).encode('ASCII', 'ignore') | |
116 | r = '' | |
117 | for c in s: | |
118 | if ('a' <= c.lower() <= 'z') or ('0' <= c <= '9'): | |
119 | r += c | |
120 | elif len(r) > 0 and r[-1] != replacement_char: | |
121 | r += replacement_char | |
122 | else: # r == '' or r[-1] == replacement_char | |
123 | pass | |
124 | return r.strip(replacement_char) | |
125 | ||
126 | def _make_wcs_cache_name(domain, form, name): | |
127 | return 'wcs-%s-%s-%s' % (domain, form, name) | |
128 | ||
129 | def set_wcs_cache(domain, form, name, data): | |
130 | os.umask(0022) | |
131 | cache_filename = _make_wcs_cache_name(domain, form, name) | |
132 | f = open(os.path.join(WCS_CACHE_DIR, cache_filename), 'wb') | |
133 | f.write(data) | |
134 | f.close() | |
135 | ||
136 | def get_wcs_cache(domain, form, name): | |
137 | data = None | |
138 | cache_filename = _make_wcs_cache_name(domain, form, name) | |
139 | cache_filename = os.path.join(WCS_CACHE_DIR, cache_filename) | |
140 | if os.path.exists(cache_filename): | |
141 | f = open(cache_filename, 'rb') | |
142 | data = f.read() | |
143 | f.close() | |
144 | return data | |
145 | ||
146 | def clear_wcs_cache(domain, form): | |
147 | cache_filename = _make_wcs_cache_name(domain, form, '') | |
148 | for f in os.listdir(WCS_CACHE_DIR): | |
149 | if f.startswith(cache_filename): | |
150 | os.unlink(os.path.join(WCS_CACHE_DIR, f)) | |
151 | ||
152 | def get_wcs_domains(): | |
153 | root = WCS_ROOT_DIR | |
154 | suffix = WCS_DOMAIN_SUFFIX | |
155 | try: | |
156 | l = os.listdir(root) | |
157 | except OSError: | |
158 | return None | |
159 | return [x for x in l if os.path.isdir(os.path.join(root, x)) and x.endswith(suffix)] | |
160 | ||
161 | def get_wcs_forms(domain): | |
162 | root = os.path.join(WCS_ROOT_DIR, domain) | |
163 | prefix = WCS_FORM_PREFIX | |
164 | try: | |
165 | l = os.listdir(root) | |
166 | except OSError: | |
167 | return None | |
168 | return [x[len(prefix):] for x in l if os.path.isdir(os.path.join(root, x)) and x.startswith(prefix)] | |
169 | ||
170 | ||
171 | def get_wcs_form_data(domain, form): | |
172 | """extraction des données du formulaire""" | |
173 | data = get_wcs_cache(domain, form, 'metadata.json') | |
174 | if data is not None: | |
175 | return json.loads(data, encoding='utf-8') | |
176 | # dictionnaire des metadonnées (qui seront mises en cache) | |
177 | metadata = {} | |
178 | ||
179 | os.umask(0022) | |
180 | logname = _make_wcs_cache_name(domain, form, 'last-run.log') | |
181 | logging.basicConfig(level=logging.DEBUG, | |
182 | format='%(asctime)s %(levelname)s %(message)s', | |
183 | filename=os.path.join(WCS_CACHE_DIR, logname), | |
184 | filemode='w') | |
185 | ||
186 | logging.info('Début.') | |
187 | ||
188 | from wcs import publisher | |
189 | from wcs.formdef import FormDef | |
190 | from wcs.fields import TitleField, CommentField, TextField, \ | |
191 | StringField, ItemField, ItemsField, EmailField, \ | |
192 | DateField, FileField, BoolField, TableField | |
193 | ||
194 | pub = publisher.WcsPublisher.create_publisher() | |
195 | pub.app_dir = os.path.join(pub.app_dir, domain) | |
196 | formdef = FormDef.get_by_urlname(form) | |
197 | ||
198 | # nommage des champs de façon unique | |
199 | fields = {} | |
200 | field_names = {} | |
201 | field_names_duplicates = {} | |
202 | for field in formdef.fields: | |
203 | if isinstance(field, TitleField) or isinstance(field, CommentField): | |
204 | continue | |
205 | if field.varname: | |
206 | name = field.varname | |
207 | else: | |
208 | name = _reduce_to_alnum(field.label,'_').lower() | |
209 | if name in field_names.values(): # duplicat | |
210 | field_names_duplicates[name] = field_names_duplicates.get(name, 1) + 1 | |
211 | name = '%s_%d' % (name, field_names_duplicates[name]) | |
212 | field_names.update({field.id: name}) | |
213 | fields.update({field.id: {'name': field_names[field.id], 'label': field.label, 'varname': field.varname and field.varname or ''}}) | |
214 | ||
215 | data = json.dumps(fields, ensure_ascii=False).encode('utf-8') | |
216 | set_wcs_cache(domain, form, 'fields.json', data) | |
217 | metadata.update({'fields': fields}) | |
218 | ||
219 | # on charge la base des types MIME une fois pour toutes | |
220 | #magicmime = magic.Magic(mime=True) => ce sera pour plus tard… | |
221 | magicmime = magic.open(magic.MAGIC_MIME) | |
222 | magicmime.load() | |
223 | ||
224 | liste_dossiers = [] | |
225 | liste_attachements = {} | |
226 | for object in formdef.data_class().select(): | |
227 | if object.user is None: | |
228 | logging.warning("Dossier '%s' sans utilisateur associé ?!?"\ | |
229 | " On ignore...", object.id) | |
230 | continue | |
231 | ||
232 | result = { | |
233 | 'num_dossier': object.id, | |
234 | 'wcs_status': object.status, | |
235 | 'wcs_workflow_status': (object.status.startswith('wf-') and \ | |
236 | object.get_workflow_status().name or None), | |
237 | 'wcs_user_email': object.user.email, | |
238 | 'wcs_user_display_name': object.user.display_name, | |
239 | #'wcs_last_modified': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(object.last_modified())), | |
240 | 'wcs_comments': [], | |
241 | } | |
242 | ||
243 | if object.evolution is not None: | |
244 | for e in object.evolution: | |
245 | if e.comment is not None: | |
246 | who = pub.user_class.get(e.who).display_name | |
247 | e_time = time.strftime('%Y-%m-%d %H:%M:%S', e.time) | |
248 | comment = '%s -- %s %s' % (e.comment, who, e_time) | |
249 | result['wcs_comments'].append(comment) | |
250 | ||
251 | qfiles = { } | |
252 | for field in formdef.fields: | |
253 | field_id = str(field.id) | |
254 | if not field_id in object.data: | |
255 | continue | |
256 | if isinstance(field, TitleField) or isinstance(field, CommentField): | |
257 | continue | |
258 | field_name = fields[field_id]['name'] | |
259 | data = object.data.get(field_id) | |
260 | if data is None: | |
261 | result[field_name] = None | |
262 | continue | |
263 | if isinstance(field, StringField) or isinstance(field, TextField) \ | |
264 | or isinstance(field, EmailField) or isinstance(field, ItemField): | |
265 | result[field_name] = data | |
266 | elif isinstance(field, ItemsField) or isinstance(field, TableField): | |
267 | result[field_name] = data # liste => peux-être joindre sur ';' | |
268 | elif isinstance(field, BoolField): | |
269 | result[field_name] = (data == 'True') | |
270 | elif isinstance(field, DateField): | |
271 | if isinstance(data, time.struct_time): | |
272 | result[field_name] = '%04d-%02d-%02d' % (data.tm_year, | |
273 | data.tm_mon, data.tm_mday) | |
274 | else: | |
275 | result[field_name] = data | |
276 | elif isinstance(field, FileField): | |
277 | if '.' in data.orig_filename: | |
278 | extension = data.orig_filename.rpartition('.')[2].lower() | |
279 | else: # il n'y a pas d'extension dans le nom de fichier | |
280 | p = os.path.join(pub.app_dir, 'uploads', data.qfilename) | |
281 | try: | |
282 | #m = magicmime.from_file(p) => ce sera pour plus tard… | |
283 | m = magicmime.file(p).split()[0].strip(';') | |
284 | extension = mimetypes.guess_extension(m) | |
285 | except: | |
286 | logging.warning("Type de fichier inconnu pour '%s'.", p) | |
287 | extension = None | |
288 | if extension is not None: | |
289 | extension = extension[1:] | |
290 | else: | |
291 | extension = 'unknown' | |
292 | result[field_name] = "%s.%s" % (field_name, extension) | |
293 | qfiles[field_name] = data.qfilename | |
294 | else: | |
295 | logging.warning("Type de champ inconnu '%s' pour '%s' (%s).", | |
296 | field.__class__.__name__, field_name, field.label) | |
297 | ||
298 | num_dossier = result['num_dossier'] | |
299 | nom = _reduce_to_alnum(result.get('nom','sans-nom')).upper() | |
300 | prenom = _reduce_to_alnum(result.get('prenom','sans-prenom')).upper() | |
301 | adel = result.get('adresse_electronique','sans-adel').replace('@','-').lower() | |
302 | ||
303 | filename = "%04d-%s-%s-%s" % (num_dossier, nom, prenom, adel) | |
304 | liste_dossiers.append(filename + '.json') | |
305 | ||
306 | # sauvegarde des chemins d'accès aux fichiers joints | |
307 | for f in qfiles: | |
308 | dst = filename + '_' + result[f] | |
309 | src = os.path.join(pub.app_dir, 'uploads', qfiles[f]) | |
310 | liste_attachements.update({dst: src}) | |
311 | ||
312 | # génération du fichier JSON | |
313 | data = json.dumps(result, ensure_ascii=False).encode('utf-8') | |
314 | set_wcs_cache(domain, form, 'data_%s.json' % filename, data) | |
315 | ||
316 | logging.info("Dossier '%s' : %s.", | |
317 | filename, result['wcs_workflow_status']) | |
318 | ||
319 | data = json.dumps(liste_attachements, ensure_ascii=False).encode('utf-8') | |
320 | set_wcs_cache(domain, form, 'data-files.json', data) | |
321 | metadata.update({'attachements': liste_attachements}) | |
322 | ||
323 | liste_dossiers.sort() | |
324 | data = json.dumps(liste_dossiers, ensure_ascii=False).encode('utf-8') | |
325 | set_wcs_cache(domain, form, 'liste-dossiers.json', data) | |
326 | metadata.update({'dossiers': liste_dossiers}) | |
327 | ||
328 | logging.info('Fin.') | |
329 | ||
330 | data = json.dumps(metadata, ensure_ascii=False).encode('utf-8') | |
331 | set_wcs_cache(domain, form, 'metadata.json', data) | |
332 | ||
333 | #if __name__ == '__main__': | |
334 | # try: | |
335 | # extract_data(formdef, OUTPUT_DIRECTORY) | |
336 | # except: | |
337 | # logging.exception("Interruption du traitement pour cause d'erreur !") | |
338 | ||
339 | #-------------------------------------------------------------------------- | |
340 | # gestion des requêtes web | |
341 | #-------------------------------------------------------------------------- | |
342 | ||
343 | #l = [] | |
344 | #for k in sorted(os.environ): | |
345 | # l.append('%s=%s\n' % (k, os.environ[k])) | |
346 | #data = ''.join(l) | |
347 | #http_reply_and_exit(data, 'text/plain') | |
348 | ||
349 | domain = os.environ.get('HTTP_HOST', '') | |
350 | if domain not in get_wcs_domains(): | |
351 | http_reply_and_exit("Domaine '%s' inconnu." % domain, 'text/plain') | |
352 | ||
353 | path_info = os.environ.get('PATH_INFO', '') | |
354 | ||
355 | path_prefix = os.environ.get('REQUEST_URI', '') | |
356 | if len(path_info) > 0: | |
357 | path_prefix = path_prefix[:-len(path_info)] | |
358 | ||
359 | if path_info == '': | |
360 | http_redirect(path_prefix + '/') | |
361 | ||
362 | if path_info == '/': | |
363 | # liste des formulaires disponibles | |
364 | l = sorted(get_wcs_forms(domain)) | |
365 | l = ['<li><a href="%s/">%s</a></li>' % (f, f) for f in l] | |
366 | title = '<p>Liste des formulaires disponibles :</p>\n' | |
367 | data = '<html>\n' + title + '<ul>\n' + '\n'.join(l) + '\n</ul>\n</html>' | |
368 | http_reply_and_exit(data, 'text/html') | |
369 | ||
370 | if path_info == '/index.json': | |
371 | # liste des formulaires disponibles | |
372 | l = sorted(get_wcs_forms(domain)) | |
373 | data = json.dumps(l, ensure_ascii=False, indent=' ').encode('utf-8') | |
374 | http_reply_and_exit(data, 'application/json') | |
375 | ||
376 | if path_info == '/domains.json': | |
377 | # liste des domaines disponibles | |
378 | l = get_wcs_domains() | |
379 | data = json.dumps(l, ensure_ascii=False, indent=' ').encode('utf-8') | |
380 | http_reply_and_exit(data, 'application/json') | |
381 | ||
382 | if match(r'^/[a-z0-9-]+$', path_info): | |
383 | http_redirect(path_prefix + path_info + '/') | |
384 | ||
385 | if match(r'^/[a-z0-9-]+/$', path_info): | |
386 | form = path_info.split('/')[1] | |
387 | if form not in get_wcs_forms(domain): | |
388 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
389 | l = [ 'fields.json', 'field-names.json', 'field-names.txt', 'last-run.log', 'liste-dossiers.json' ] | |
390 | l = ['<li><a href="%s">%s</a></li>' % (f, f) for f in l] | |
391 | title = '<p>Liste des informations disponibles :</p>\n' | |
392 | action1 = """<p><a href="data/">Export des données</a></p>\n""" | |
393 | action2 = """<p><a href="clear-cache">Suppression du cache</a> (pour ré-export)</p>\n""" | |
394 | data = '<html>\n' + title + '<ul>\n' + '\n'.join(l) + '\n</ul>\n' + action1 + action2 + '</html>' | |
395 | http_reply_and_exit(data, 'text/html') | |
396 | ||
397 | if match(r'^/[a-z0-9-]+/index.json$', path_info): | |
398 | form = path_info.split('/')[1] | |
399 | if form not in get_wcs_forms(domain): | |
400 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
401 | l = [ 'fields.json', 'field-names.json', 'field-names.txt', 'last-run.log', 'liste-dossiers.json', 'data', 'clear-cache' ] | |
402 | data = json.dumps(l, ensure_ascii=False, indent=' ').encode('utf-8') | |
403 | http_reply_and_exit(data, 'application/json') | |
404 | ||
405 | if match(r'^/[a-z0-9-]+/clear-cache$', path_info): | |
406 | form = path_info.split('/')[1] | |
407 | if form not in get_wcs_forms(domain): | |
408 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
409 | clear_wcs_cache(domain, form) | |
410 | http_reply_and_exit('Ok.', 'text/plain') | |
411 | ||
412 | if match(r'^/[a-z0-9-]+/fields.json$', path_info): | |
413 | form = path_info.split('/')[1] | |
414 | if form not in get_wcs_forms(domain): | |
415 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
416 | get_wcs_form_data(domain, form) | |
417 | d = json.loads(get_wcs_cache(domain, form, 'fields.json'), encoding='utf-8') | |
418 | data = json.dumps(d, ensure_ascii=False, indent=' ').encode('utf-8') | |
419 | http_reply_and_exit(data, 'application/json') | |
420 | ||
421 | if match(r'^/[a-z0-9-]+/field-names.json$', path_info): | |
422 | form = path_info.split('/')[1] | |
423 | if form not in get_wcs_forms(domain): | |
424 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
425 | get_wcs_form_data(domain, form) | |
426 | d = json.loads(get_wcs_cache(domain, form, 'fields.json'), encoding='utf-8') | |
427 | d = dict([(k, d[k]['name']) for k in d]) | |
428 | data = json.dumps(d, ensure_ascii=False, indent=' ').encode('utf-8') | |
429 | http_reply_and_exit(data, 'application/json') | |
430 | ||
431 | if match(r'^/[a-z0-9-]+/field-names.txt$', path_info): | |
432 | form = path_info.split('/')[1] | |
433 | if form not in get_wcs_forms(domain): | |
434 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
435 | get_wcs_form_data(domain, form) | |
436 | d = json.loads(get_wcs_cache(domain, form, 'fields.json'), encoding='utf-8') | |
437 | d = [(k, d[k]['name'], d[k]['label']) for k in d] | |
438 | d = sorted(d, key=lambda x: int(x[0])) | |
439 | text = u''.join([u'%s:%s:%s\n' % (x[0], x[1], x[2]) for x in d]) | |
440 | data = text.encode('utf-8') | |
441 | http_reply_and_exit(data, 'text/plain') | |
442 | ||
443 | if match(r'^/[a-z0-9-]+/last-run.log$', path_info): | |
444 | form = path_info.split('/')[1] | |
445 | if form not in get_wcs_forms(domain): | |
446 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
447 | get_wcs_form_data(domain, form) | |
448 | data = get_wcs_cache(domain, form, 'last-run.log') | |
449 | http_reply_and_exit(data, 'text/plain') | |
450 | ||
451 | if match(r'^/[a-z0-9-]+/liste-dossiers.json$', path_info): | |
452 | form = path_info.split('/')[1] | |
453 | if form not in get_wcs_forms(domain): | |
454 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
455 | get_wcs_form_data(domain, form) | |
456 | data = json.loads(get_wcs_cache(domain, form, 'liste-dossiers.json'), encoding='utf-8') | |
457 | data = json.dumps(data, ensure_ascii=False, indent=' ').encode('utf-8') | |
458 | http_reply_and_exit(data, 'application/json') | |
459 | ||
460 | if match(r'^/[a-z0-9-]+/data$', path_info): | |
461 | http_redirect(path_prefix + path_info + '/') | |
462 | ||
463 | if match(r'^/[a-z0-9-]+/data/$', path_info): | |
464 | form = path_info.split('/')[1] | |
465 | if form not in get_wcs_forms(domain): | |
466 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
467 | get_wcs_form_data(domain, form) | |
468 | dossiers = json.loads(get_wcs_cache(domain, form, 'liste-dossiers.json'), encoding='utf-8') | |
469 | attachements = json.loads(get_wcs_cache(domain, form, 'data-files.json'), encoding='utf-8') | |
470 | l = sorted(dossiers + attachements.keys()) | |
471 | if len(l) > 0: | |
472 | l = ['<li><a href="%s">%s</a></li>' % (f, f) for f in l] | |
473 | title = '<p>Liste des documents disponibles :</p>\n' | |
474 | data = '<html>\n' + title + '<ul>\n' + '\n'.join(l) + '\n</ul>\n</html>' | |
475 | else: | |
476 | data = '<html>\n<p>Aucun document disponible.</p>\n</html>' | |
477 | http_reply_and_exit(data, 'text/html') | |
478 | ||
479 | if match(r'^/[a-z0-9-]+/data/index.json$', path_info): | |
480 | form = path_info.split('/')[1] | |
481 | if form not in get_wcs_forms(domain): | |
482 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
483 | get_wcs_form_data(domain, form) | |
484 | dossiers = json.loads(get_wcs_cache(domain, form, 'liste-dossiers.json'), encoding='utf-8') | |
485 | attachements = json.loads(get_wcs_cache(domain, form, 'data-files.json'), encoding='utf-8') | |
486 | l = sorted(dossiers + attachements.keys()) | |
487 | data = json.dumps(l, ensure_ascii=False, indent=' ').encode('utf-8') | |
488 | http_reply_and_exit(data, 'application/json') | |
489 | ||
490 | if match(r'^/[a-z0-9-]+/data/[^/]+$', path_info): | |
491 | form = path_info.split('/')[1] | |
492 | if form not in get_wcs_forms(domain): | |
493 | http_reply_and_exit("Formulaire '%s' inconnu." % form, 'text/plain') | |
494 | get_wcs_form_data(domain, form) | |
495 | doc = path_info.split('/')[3] | |
496 | dossiers = json.loads(get_wcs_cache(domain, form, 'liste-dossiers.json'), encoding='utf-8') | |
497 | if doc in dossiers: | |
498 | data = get_wcs_cache(domain, form, 'data_' + doc) | |
499 | data = json.loads(data, encoding='utf-8') | |
500 | data = json.dumps(data, ensure_ascii=False, indent=' ').encode('utf-8') | |
501 | http_reply_and_exit(data, 'application/json') | |
502 | attachements = json.loads(get_wcs_cache(domain, form, 'data-files.json'), encoding='utf-8') | |
503 | if doc in attachements: | |
504 | data = open(attachements[doc], 'rb').read() | |
505 | mime_type = mimetypes.guess_type(doc)[0] | |
506 | if mime_type is None: | |
507 | mime_type = 'application/octet-stream' | |
508 | http_reply_and_exit(data, mime_type) | |
509 | http_reply_and_exit("Document '%s' inconnu." % path_info, 'text/plain') | |
510 | ||
511 | http_reply_and_exit("Requête '%s' inconnue." % path_info, 'text/plain') |