72b8e3759058b97f5c54499f65a7d60e33f37824
[progfou.git] / wcs / wcs-extract
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import os
5 import os.path
6 import shutil
7 import logging
8 from time import gmtime, strftime
9 import simplejson as json
10
11 from wcs import publisher
12 from wcs.formdef import FormDef
13 from wcs.fields import TitleField, CommentField, TextField, \
14                        StringField, ItemField, EmailField, \
15                        DateField, FileField, BoolField
16
17
18 def reduce_to_alnum(s, replacement_char='-'):
19     """réduction d'une chaîne de caractères à de l'alpha-numérique"""
20
21     avec_accent = u'çÇáàâÁÀÂéèêëÉÈÊËíìîïÍÌÎÏóòôöÓÒÔÖúùûüÚÙÛÜýỳyÿÝỲYŸ'
22     sans_accent = u'cCaaaAAAeeeeEEEEiiiiIIIIooooOOOOuuuuUUUUyyyyYYYY'
23     if type(s) is not unicode:
24         s = unicode(s, 'utf-8')
25         u  = False
26     r = ''
27     for c in s:
28         index = avec_accent.find(c)
29         if index >= 0:
30             r += sans_accent[index]
31         elif ('a' <= c.lower() <= 'z') or ('0' <= c <= '9'):
32             r += c
33         elif len(r) > 0 and r[-1] != replacement_char:
34             r += replacement_char
35         else: # r == '' or r[-1] == replacement_char
36             pass
37     r = r.strip(replacement_char)
38     if not u:
39         r = r.encode('utf-8')
40     return r
41
42
43 def extract_fields(formdef, output_directory):
44     """nommage des champs de façon unique"""
45     # TODO: devrait retourner un résultat, qui serait alors sauvé en dehors
46
47     # XXX: hack temporaire… :-/
48     global field_names
49
50     f = open(os.path.join(output_directory, 'field-names.txt'), 'w')
51
52     field_names = {}
53     field_names_duplicates = {}
54     for field in formdef.fields:
55         if isinstance(field, TitleField) or isinstance(field, CommentField):
56             continue
57         name = reduce_to_alnum(field.label,'_').lower()
58         if name in field_names.values(): # duplicat
59             field_names_duplicates[name] = field_names_duplicates.get(name, 1) + 1
60             name = '%s_%d' % (name, field_names_duplicates[name])
61         field_names.update({field.id: name})
62         print >>f, "%s:%s:%s" % (field.id, field_names[field.id], field.label)
63
64     f.close()
65
66     f = open(os.path.join(output_directory, 'field-names.json'), 'wb')
67     f.write(json.dumps(field_names, ensure_ascii=False))
68     f.close()
69
70
71 def extract_data(formdef, output_directory):
72     """extraction des données du formulaire"""
73     # TODO: devrait retourner un résultat, qui serait alors sauvé en dehors
74
75     # XXX: hack temporaire… :-/
76     global pub
77
78     liste_dossiers = []
79     for object in formdef.data_class().select():
80         result = {
81             'num_dossier': object.id,
82             'wcs_status': object.status,
83             'wcs_workflow_status': object.get_workflow_status().name,
84             'wcs_user_email': object.user.email,
85             'wcs_user_display_name': object.user.display_name,
86            #'wcs_last_modified': strftime('%Y-%m-%d %H:%M:%S', gmtime(object.last_modified())),
87             'wcs_comments': [],
88         }
89
90         if object.evolution is not None:
91             for e in object.evolution:
92                 if e.comment is not None:
93                     who = pub.user_class.get(e.who).display_name
94                     time = strftime('%Y-%m-%d %H:%M:%S', e.time)
95                     comment = '%s -- %s %s' % (e.comment, who, time)
96                     result['wcs_comments'].append(comment)
97
98         qfiles = { }
99         for field in formdef.fields:
100             field_id = str(field.id)
101             if not field_id in object.data:
102                 continue
103             if isinstance(field, TitleField) or isinstance(field, CommentField):
104                 continue
105             field_name = field_names[field_id]
106             data = object.data.get(field_id)
107             if isinstance(field, StringField) or isinstance(field, TextField) \
108             or isinstance(field, EmailField) or isinstance(field, ItemField):
109                 result[field_name] = data
110             elif isinstance(field, BoolField):
111                 result[field_name] = (data == 'True')
112             elif isinstance(field, DateField):
113                 result[field_name] = strftime('%Y-%m-%d', data)
114             elif isinstance(field, FileField):
115                 extension = data.orig_filename.rpartition('.')[2].lower()
116                 result[field_name] = "%s.%s" % (field_name, extension)
117                 qfiles[field_name] = data.qfilename
118             else:
119                 logging.error("Type de champ inconnu '%s' pour '%s'.",
120                                     field.__class__.__name__, field.label)
121                 raise RuntimeError
122
123         num_dossier = result['num_dossier']
124         nom = reduce_to_alnum(result['nom']).upper()
125         prenom = reduce_to_alnum(result['prenom']).upper()
126         adel = result['adresse_electronique'].replace('@','-').lower()
127
128         filename = "%04d-%s-%s-%s" % (num_dossier, nom, prenom, adel)
129         liste_dossiers.append(filename + '.json')
130
131         # copie des fichiers joints
132         for f in qfiles:
133             result[f] = filename + '_' + result[f]
134             src = os.path.join(pub.app_dir, 'uploads', qfiles[f])
135             dst = os.path.join(output_directory, 'data', result[f])
136             if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
137                 shutil.copy2(src, dst)
138                 os.chmod(dst, 0644)
139
140         # génération du fichier JSON
141         jsonname = os.path.join(output_directory, 'data', filename + '.json')
142         f = open(jsonname, 'wb')
143         f.write(json.dumps(result, ensure_ascii=False))
144         f.close()
145
146         logging.info("Dossier '%s' : %s.",
147                                     filename, result['wcs_workflow_status'])
148
149     f = open(os.path.join(output_directory, 'liste-dossiers.json'), 'wb')
150     f.write(json.dumps(liste_dossiers, ensure_ascii=False))
151     f.close()
152
153
154 if __name__ == '__main__':
155     import sys
156
157     if len(sys.argv) != 4:
158         print >>sys.stderr, "Usage : %s <dossier-destination> <site> <formulaire>" % sys.argv[0]
159         sys.exit(1)
160
161     VHOST = sys.argv[2]
162     FORM_NAME = sys.argv[3]
163     OUTPUT_DIRECTORY = os.path.join(sys.argv[1], VHOST, FORM_NAME)
164
165     os.umask(0022)
166     # création du dossier d'extraction, au besoin
167     if not os.path.isdir(OUTPUT_DIRECTORY):
168         os.makedirs(OUTPUT_DIRECTORY, 0755)
169
170     logging.basicConfig(level=logging.DEBUG,
171         format='%(asctime)s %(levelname)s %(message)s',
172         filename=os.path.join(OUTPUT_DIRECTORY, 'last-run.log'),
173         filemode='w')
174
175     logging.info('Début.')
176
177     pub = publisher.WcsPublisher.create_publisher()
178     pub.app_dir = os.path.join(pub.app_dir, VHOST)
179
180     formdef = FormDef.get_by_urlname(FORM_NAME)
181
182     extract_fields(formdef, OUTPUT_DIRECTORY)
183
184     extract_data(formdef, OUTPUT_DIRECTORY)
185
186     logging.info('Fin.')
187