w.c.s : nouvelle version des outils de gestion hors-ligne
authorProgfou <jean-christophe.andre@auf.org>
Mon, 13 Dec 2010 00:07:11 +0000 (07:07 +0700)
committerProgfou <jean-christophe.andre@auf.org>
Mon, 13 Dec 2010 00:07:11 +0000 (07:07 +0700)
wcs/courriel-Thomas.txt [deleted file]
wcs/demande-de-bourse-de-doctorat-2010-2011_field-names.txt [deleted file]
wcs/wcs-extract.py [new file with mode: 0644]
wcs/wcs-extract.sh [new file with mode: 0755]
wcs/wcs-status.py [new file with mode: 0755]
wcs/wcs2json.py [deleted file]
wcs/wcs2json.sh [deleted file]

diff --git a/wcs/courriel-Thomas.txt b/wcs/courriel-Thomas.txt
deleted file mode 100644 (file)
index c5e0395..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-Ce que j'attends :
-
-- un fichier   nnn-prenom-nom-email_domaine.json
-  pour chaque dossier "nnn"
-
-- dans ce fichier, quelque chose comme :
-
-  { 
-    'num_dossier': 134,
-    'nom': 'NOËL',
-    'prenom' : 'Thomas'
-    'date_naissance': '18/04/1973',
-    'nom_responsable_origine' : 'Leblanc',
-    ...
-  }
-
-c'est-à-dire qu'on cherche à avoir des intitulés clairs pour chaque champs du
-formulaire. Autrement dit, on renomme les noms du style "f652" de wcs.
-
-Par ailleurs, quelques traitement spéciaux en fonction de certains
-type de champ :
-
-PAYS
-====
-Quand dans WCS on a un pays du genre 
-
-    f_44 = "Sénégal (SN - Afrique de l'Ouest)"
-  il faut que dans notre JSON cela donne :
-    pays_nationalite_iso = 'SN',
-    pays_nationalite_nom = 'Sénégal',
-    pays_nationalite_region = "Afrique de l'Ouest",
-    pays_nationalite_code_region = 'AO',
-
-
-ETABLISSEMENTS
-==============
-Quand on a un établissement :
-    f_54 = "Algérie - Ecole machin (65 - Sud)"
-  il faut que ça donne :
-    etab_origine_code = '65'
-    etab_origine_sudnord = 'Sud'
-    etab_origine_nom = 'Ecole machin'
-    etab_origine_pays = 'Algérie'
-    etab_origine_pays_iso = 'DZ'
-    etab_origine_region = 'Europe Ouest et Maghreb'
-    etab_origine_code_region = 'EOM'
-
-
-NB : il nous faut donc, dans ce dernier cas, une association Pays/Région,
-celle qui est visible sur le réglement des bourses.
-
-DOC ATTACHES
-============
-Enfin, concernant les doc attachés, idéalement on aurait dans le JSON :
-
-   cv_url =
-'https://https://formulaires.auf.org/backoffice/demande-de-bourse-de-doctorat-2010-2011/234/download?f=103'
-   cv_filename = '0.87817287'
-   cv_realname = 'Curriculum Vitae.doc'
-
-L'URL est facile à calculer. Dans l'exemple ci-dessus on est dans le dossier
-134, et on a 3 documents :
-  ?f=101 pour le descriptif_detaille_url
-  ?f=102 pour le protocole_recherche_url
-  ?f=103 pour le cv_url
-
-
-
-
-Voilà, je pense que c'est à peu près tout. Davin, tu compléteras si tu penses
-qu'il manque des infos pour l'import SIGMA.
diff --git a/wcs/demande-de-bourse-de-doctorat-2010-2011_field-names.txt b/wcs/demande-de-bourse-de-doctorat-2010-2011_field-names.txt
deleted file mode 100644 (file)
index 24131bb..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-5:civilite
-6:nom
-7:nom_jeune_fille
-8:prenom
-9:pays_nationalite
-10:pays_naissance
-11:date_naissance
-12:ville_naissance
-14:adresse
-15:ville
-16:region
-17:code_postal
-18:pays_residence
-19:tel
-20:tel_pro
-21:email
-23:statut_personne
-24:fonction
-26:intitule_d_diplome
-27:date_d_diplome
-28:nom_etb
-29:pays_etb
-30:niveau
-32:particip_prog_auf
-33:particip_prog_auf_dernier
-34:particip_prog_auf_annee
-35:boursier_auf
-36:boursier_auf_type
-37:boursier_auf_annee
-39:programme
-40:programme_autre
-41:annee_programme
-44:o_etablissement_unite
-45:o_sc_civilite
-46:o_sc_nom
-47:o_sc_prenom
-48:o_sc_fonction
-49:o_sc_ville
-50:o_sc_tel_pro
-51:o_sc_email
-53:o_inst_civilite
-54:o_inst_nom
-55:o_inst_prenom
-56:o_inst_email
-59:a_etablissement_unite
-60:a_sc_civilite
-61:a_sc_nom
-62:a_sc_prenom
-63:a_sc_fonction
-64:a_sc_ville
-65:a_sc_tel_pro
-66:a_sc_email
-68:a_inst_civilite
-69:a_inst_nom
-70:a_inst_prenom
-71:a_inst_email
-75:o_date_debut_mobilite
-76:o_date_fin_mobilite
-77:o_nb_mois
-79:a_date_debut_mobilite
-80:a_date_fin_mobilite
-81:a_nb_mois
-83:date_inscription_these
-84:date_soutenance_these
-85:pays_soutenance
-86:type_these
-87:discipline
-88:intitule_projet
-90:mot_clef1
-91:mot_clef2
-92:mot_clef3
-95:engagement_nom
-96:engagement_prenom
-98:engagement_respect_reglement
-101:descriptif_these
-102:protocole_recherche
-103:curriculum_vitae
-108:a_etablissement
-109:o_etablissement
diff --git a/wcs/wcs-extract.py b/wcs/wcs-extract.py
new file mode 100644 (file)
index 0000000..9638fbe
--- /dev/null
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import os.path
+import sys
+from time import gmtime, strftime
+import simplejson as json
+
+if len(sys.argv) != 4:
+    print sys.stderr, "Usage : %s <dossier-destination> <site> <formulaire>" % sys.argv[0]
+    sys.exit(1)
+VHOST = sys.argv[2]
+FORM_NAME = sys.argv[3]
+OUTPUT_DIRECTORY = os.path.join(sys.argv[1], VHOST, FORM_NAME)
+
+os.umask(0022)
+# création du dossier d'extraction, au besoin
+if not os.path.isdir(OUTPUT_DIRECTORY):
+    os.makedirs(OUTPUT_DIRECTORY, 0755)
+
+TIME_FORMAT = "%Y-%m-%d"
+TIME_FORMAT_LONG = "%Y-%m-%d %H:%M:%S"
+
+# fonction de nettoyage des noms pour ne garder que de l'alpha-numérique
+def cleanup(s, replacement_char='-'):
+    avec_accent = u'çÇáàâÁÀÂéèêëÉÈÊËíìîïÍÌÎÏóòôöÓÒÔÖúùûüÚÙÛÜýỳyÿÝỲYŸ'
+    sans_accent = u'cCaaaAAAeeeeEEEEiiiiIIIIooooOOOOuuuuUUUUyyyyYYYY'
+    if type(s) is not unicode:
+        s = unicode(s, 'utf-8')
+        u  = False
+    r = ''
+    for c in s:
+        index = avec_accent.find(c)
+        if index >= 0:
+            r += sans_accent[index]
+        elif ('a' <= c.lower() <= 'z') or ('0' <= c <= '9'):
+            r += c
+        elif len(r) > 0 and r[-1] != replacement_char:
+            r += replacement_char
+        else: # r == '' or r[-1] == replacement_char
+            pass
+    r = r.strip(replacement_char)
+    if not u:
+        r = r.encode('utf-8')
+    return r
+
+from wcs import publisher
+from wcs.formdef import FormDef
+from wcs.fields import TitleField, CommentField, TextField, \
+                       StringField, ItemField, EmailField, \
+                       DateField, FileField, BoolField
+
+pub = publisher.WcsPublisher.create_publisher()
+pub.app_dir = os.path.join(pub.app_dir, VHOST)
+
+formdef = FormDef.get_by_urlname(FORM_NAME)
+
+#
+# nommage des champs, de façon unique
+#
+
+f = open(os.path.join(OUTPUT_DIRECTORY, 'field-names.txt'), 'w')
+
+field_names = {}
+field_names_duplicates = {}
+for field in formdef.fields:
+    if isinstance(field, TitleField) or isinstance(field, CommentField):
+        continue
+    name = cleanup(field.label,'_').lower()
+    if name in field_names.values(): # duplicat
+        field_names_duplicates[name] = field_names_duplicates.get(name, 1) + 1
+        name = '%s_%d' % (name, field_names_duplicates[name])
+    field_names.update({field.id: name})
+    print >>f, "%s:%s:%s" % (field.id, field_names[field.id], field.label)
+
+f.close()
+
+f = open('%s/field-names.json' % OUTPUT_DIRECTORY, 'wb')
+f.write(json.dumps(field_names, ensure_ascii=False))
+f.close()
+
+#
+# extraction des données
+#
+
+for object in formdef.data_class().select():
+    result = {
+        'num_dossier': object.id,
+        'wcs_status': object.status,
+        'wcs_workflow_status': object.get_workflow_status().name,
+        'wcs_user_email': object.user.email,
+        'wcs_user_display_name': object.user.display_name,
+       #'wcs_last_modified': strftime(TIME_FORMAT_LONG, gmtime(object.last_modified())),
+    }
+    qfiles = { }
+    for field in formdef.fields:
+        field_id = str(field.id)
+        if not field_id in object.data:
+            continue
+        if isinstance(field, TitleField) or isinstance(field, CommentField):
+            continue
+        field_name = field_names[field_id]
+        data = object.data.get(field_id)
+        if isinstance(field, StringField) or isinstance(field, TextField) \
+        or isinstance(field, EmailField) or isinstance(field, ItemField):
+            result[field_name] = data
+        elif isinstance(field, BoolField):
+            result[field_name] = (data == 'True')
+        elif isinstance(field, DateField):
+            result[field_name] = strftime(TIME_FORMAT, data)
+        elif isinstance(field, FileField):
+            extension = data.orig_filename.rpartition('.')[2].lower()
+            result[field_name] = "%s.%s" % (field_name, extension)
+            qfiles[field_name] = data.qfilename
+        else:
+            print "WARNING: unknown field type '%s' for '%s'" % \
+                                    (field.__class__.__name__, field.label)
+            raise RuntimeError
+
+    num_dossier = result['num_dossier']
+    nom = cleanup('-'.join(result['nom'].split()).upper())
+    prenom = cleanup('-'.join(result['prenom'].split()).upper())
+    adel = result['adresse_electronique'].replace('@','-').lower()
+
+    filename = "%04d-%s-%s-%s" % (num_dossier, nom, prenom, adel)
+
+    print "Dossier '%s'..." % filename,
+
+    for f in qfiles:
+        result[f] = '%s_%s' % (filename, result[f])
+        src = '%s/uploads/%s' % (pub.app_dir, qfiles[f])
+        dst = '%s/%s' % (OUTPUT_DIRECTORY, result[f])
+        if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
+            os.spawnl(os.P_WAIT, '/bin/cp', '-af', src, dst)
+            os.chmod(dst, 0644)
+
+    f = open('%s/%s.json' % (OUTPUT_DIRECTORY, filename), 'wb')
+    f.write(json.dumps(result, ensure_ascii=False))
+    f.close()
+
+    print "OK."
+
+f = open('%s/last-run.txt' % OUTPUT_DIRECTORY, 'w')
+f.write('%s GMT' % strftime(TIME_FORMAT_LONG, gmtime()))
+f.close()
diff --git a/wcs/wcs-extract.sh b/wcs/wcs-extract.sh
new file mode 100755 (executable)
index 0000000..b26fe0d
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+OUTPUT_DIR="/srv/wcs"
+SITE="formulaires.auf.org"
+FORMS="\
+ horizons-francophones-2010-bureau-ocean-indien \
+ demande-de-bourse-de-doctorat-2010-2011-algerie-maroc-tunisie \
+ demande-de-bourse-de-doctorat-2011-2012-afrique-centrale-et-des-grands-lacs \
+"
+
+# XXX: hack en attendant de corriger le umask de wcs…
+sudo chmod -R g+rX /var/lib/wcs/
+
+echo "Traitement des formulaires de '$SITE'…"
+for f in $FORMS
+do
+  echo " $f"
+  dir="$OUTPUT_DIR/$SITE/$f"
+  mkdir -p $dir
+  python wcs-extract.py $OUTPUT_DIR $SITE $f >& $dir/last-run.log
+done
+echo "Terminé.
diff --git a/wcs/wcs-status.py b/wcs/wcs-status.py
new file mode 100755 (executable)
index 0000000..4e855e9
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+
+if len(sys.argv) != 3:
+    print >>sys.stderr, "Usage : %s <site> <formulaire>" % sys.argv[0]
+    sys.exit(1)
+VHOST = sys.argv[1]
+FORM_NAME = sys.argv[2]
+
+PRINT_FORMAT = "%4s | %-17s | %-52s"
+PRINT_HEADERS = PRINT_FORMAT % ('Num.', 'Statut', 'Utilisateur')
+PRINT_BAR = "=" * len(PRINT_HEADERS)
+
+from wcs import publisher
+from wcs.formdef import FormDef
+
+pub = publisher.WcsPublisher.create_publisher()
+pub.app_dir = os.path.join(pub.app_dir, VHOST)
+
+formdef = FormDef.get_by_urlname(FORM_NAME)
+
+print PRINT_HEADERS
+print PRINT_BAR
+
+for object in formdef.data_class().select():
+    print PRINT_FORMAT % ('%04d' % object.id,
+        object.get_workflow_status().name,
+        '%s <%s>' % (object.user.display_name, object.user.email),
+    )
+
+print PRINT_BAR
diff --git a/wcs/wcs2json.py b/wcs/wcs2json.py
deleted file mode 100644 (file)
index 4e9feff..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# le nom d'hote hébergeant wcs
-VHOST = "formulaires.auf.org"
-# nom du formulaire à explorer
-FORM_NAME = "demande-de-bourse-de-doctorat-2010-2011"
-# nom des fichiers à générer (un par formulaire)
-OUTPUT_DIRECTORY = "/srv/www/wcs/%s/%s" % (VHOST, FORM_NAME)
-
-URL_BASE = "http://%s/backoffice/%s" % (VHOST, FORM_NAME)
-URL_DOWNLOAD = "%s/%s" % (URL_BASE, "%s/download?f=%s")
-#TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
-TIME_FORMAT = "%Y-%m-%d"
-
-import os
-import sys
-from wcs import publisher
-from wcs.formdef import FormDef
-from wcs.fields import TitleField, CommentField, TextField, \
-                       StringField, ItemField, EmailField, \
-                       DateField, FileField, BoolField
-from time import strftime
-from simplejson import dumps, loads
-
-def cleanup(s):
-    avec_accent = u'çÇáàâÁÀÂéèêëÉÈÊËíìîïÍÌÎÏóòôöÓÒÔÖúùûüÚÙÛÜýỳyÿÝỲYŸ'
-    sans_accent = u'cCaaaAAAeeeeEEEEiiiiIIIIooooOOOOuuuuUUUUyyyyYYYY'
-    if type(s) is not unicode:
-        s = unicode(s, 'utf-8')
-        u  = False
-    r = ''
-    for c in s:
-        index = avec_accent.find(c)
-        if index >= 0:
-            c = sans_accent[index]
-        elif c != '-' and not ('a' <= c.lower() <= 'z'):
-            c = '-'
-        r += c
-    if not u:
-        r = r.encode('utf-8')
-    return r
-
-f = open(FORM_NAME + '_field-names.txt', 'r')
-field_names = dict([l.strip().split(':') for l in f.readlines()])
-f.close()
-
-qfile_commands = open(FORM_NAME + '_copy-qfiles.sh', 'w')
-
-pub = publisher.WcsPublisher.create_publisher()
-pub.app_dir = os.path.join(pub.app_dir, VHOST)
-
-
-formdef = FormDef.get_by_urlname(FORM_NAME)
-for object in formdef.data_class().select():
-    result = { 'num_dossier': object.id }
-    qfiles = { }
-    for field in formdef.fields:
-        field_id = str(field.id)
-        if not field_id in object.data:
-            continue
-        if isinstance(field, TitleField) or isinstance(field, CommentField):
-            continue
-        field_name = field_names.get(field_id, field.label)
-        data = object.data.get(field_id)
-        if isinstance(field, StringField) or isinstance(field, TextField) \
-        or isinstance(field, EmailField):
-            result[field_name] = data
-        elif isinstance(field, ItemField):
-            if field_name.startswith('pays') or 'etablissement' in field_name:
-                index = data.find('(')
-                if index >= 0:
-                    end = data.find(' ', index+1)
-                    data = data[index+1:end]
-            elif field_name == 'discipline':
-                index = data.rfind('(')
-                if index >= 0:
-                    end = data.find(')', index+1)
-                    data = data[index+1:end]
-            #elif field_name == 'region':
-            #    index = data.rfind('(')
-            #    if index >= 0:
-            #        index = data.find('-', index+1)
-            #        end = data.find(')', index+1)
-            #        data = filter(lambda c: c.isupper(), data[index+1:end])
-            result[field_name] = data
-        elif isinstance(field, BoolField):
-            result[field_name] = (data == 'True')
-        elif isinstance(field, FileField):
-            extension = data.orig_filename.rpartition('.')[2].lower()
-            result[field_name] = "%s.%s" % (field_name, extension)
-            qfiles[field_name] = data.qfilename
-        elif isinstance(field, DateField):
-            data = strftime(TIME_FORMAT, object.data.get(field_id))
-            result[field_name] = data
-        else:
-            data = object.data.get(field_id)
-            print "WARNING: unknown field type '%s' for '%s'" % \
-                                    (field.__class__.__name__, field.label)
-            raise RuntimeError
-
-    num_dossier = result['num_dossier']
-    nom = cleanup('-'.join(result['nom'].split()).upper())
-    prenom = cleanup('-'.join(result['prenom'].split()).upper())
-    email = result['email'].replace('@','-').lower()
-
-    filename = "%s/%04d-%s-%s-%s.json" % \
-        (OUTPUT_DIRECTORY, num_dossier, nom, prenom, email)
-
-    f = open(filename, 'wb')
-    f.write(dumps(result, ensure_ascii=False))
-    f.close()
-
-    filename = filename[:-len('.json')]
-    for f in qfiles:
-        print >>qfile_commands, "cp -af '%s/uploads/%s' '%s_%s'" % \
-                        (pub.app_dir, qfiles[f], filename, result[f])
-
-qfile_commands.close()
-
diff --git a/wcs/wcs2json.sh b/wcs/wcs2json.sh
deleted file mode 100755 (executable)
index 25818b3..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-sudo chmod -R g+rX /var/lib/wcs/
-python wcs2json.py >& wcs2json.log
-tail wcs2json.log