wcs-dynexport : paliatif aux corrections de formulaires en cours de route…
[progfou.git] / wcs / wcs-dynexport
index 8792247..df72210 100755 (executable)
@@ -39,12 +39,15 @@ from cStringIO import StringIO
 from gzip import GzipFile
 from re import match
 
-DELAIS = 5 # maximum 5 secondes en cache
+EXPIRE_DELAY = 5 # maximum 5 secondes en cache web
 TIME_FORMAT = '%a, %d %b %Y %H:%M:%S GMT' # format date pour HTTP
+#ETABLISSEMENT_FORMAT = r'^(\w+\s-\s.+)\s\(\d+\s-\s(Nord|Sud)\)$'
 
 WCS_ROOT_DIR = '/var/lib/wcs'
 WCS_DOMAIN_SUFFIX = '.auf.org'
 WCS_CACHE_DIR = '/var/tmp'
+WCS_CACHE_DELAY_DEFAULT = 7*24*60*60 # 1 semaine
+WCS_CACHE_DELAY_FORMS = 5*60 # 5 minutes
 
 #--------------------------------------------------------------------------
 # variables globales
@@ -74,10 +77,11 @@ Please go to ${location}"""
     sys.exit(0)
 
 def http_reply_and_exit(data, mime_type='text/html', charset='utf-8'):
+    if data is None: data = ''
     # références horaires
     current_time = time.time()
     mtime = time.gmtime(current_time)
-    etime = time.gmtime(current_time + DELAIS)
+    etime = time.gmtime(current_time + EXPIRE_DELAY)
     if os.environ.has_key('HTTP_IF_MODIFIED_SINCE'):
         try:
             itime = time.strptime(os.environ['HTTP_IF_MODIFIED_SINCE'], TIME_FORMAT)
@@ -131,21 +135,28 @@ def _reduce_to_alnum(s, replacement_char='-'):
 def _make_wcs_cache_name(domain, form, name):
     return 'wcs-%s-%s-%s' % (domain, form, name)
 
-def set_wcs_cache(domain, form, name, data):
+def set_wcs_cache(domain, form, name, data, delay=WCS_CACHE_DELAY_DEFAULT):
     os.umask(0022)
     cache_filename = _make_wcs_cache_name(domain, form, name)
-    f = open(os.path.join(WCS_CACHE_DIR, cache_filename), 'wb')
+    cache_filename = os.path.join(WCS_CACHE_DIR, cache_filename)
+    f = open(cache_filename, 'wb')
     f.write(data)
     f.close()
+    # la date de modification est utilisée comme date d'expiration
+    atime = time.time()
+    mtime = atime + delay
+    os.utime(cache_filename, (atime, mtime))
 
 def get_wcs_cache(domain, form, name):
     data = None
     cache_filename = _make_wcs_cache_name(domain, form, name)
     cache_filename = os.path.join(WCS_CACHE_DIR, cache_filename)
     if os.path.exists(cache_filename):
-        f = open(cache_filename, 'rb')
-        data = f.read()
-        f.close()
+        # la date de modification est utilisée comme date d'expiration
+        if time.time() < os.path.getmtime(cache_filename):
+            data = open(cache_filename, 'rb').read()
+        else:
+            os.unlink(cache_filename)
     return data
 
 def clear_wcs_cache(domain, form):
@@ -172,9 +183,16 @@ def get_wcs_domains():
     return [x for x in l if os.path.isdir(os.path.join(root, x)) and x.endswith(suffix)]
 
 def get_wcs_forms(domain):
+    """extraction de la liste des formulaires"""
+    data = get_wcs_cache(domain, 'ALL', 'ALL.json')
+    if data is not None:
+        return json.loads(data, encoding='utf-8')
     set_wcs_publisher(domain)
     from wcs.formdef import FormDef
-    return [f.url_name for i,f in FormDef.items()]
+    forms = [f.url_name for i,f in FormDef.items()]
+    data = json.dumps(forms, ensure_ascii=False).encode('utf-8')
+    set_wcs_cache(domain, 'ALL', 'ALL.json', data, WCS_CACHE_DELAY_FORMS)
+    return forms
 
 def get_wcs_form_data(domain, form):
     """extraction des données du formulaire"""
@@ -186,12 +204,16 @@ def get_wcs_form_data(domain, form):
 
     os.umask(0022)
     logname = _make_wcs_cache_name(domain, form, 'last-run.log')
-    logging.basicConfig(level=logging.DEBUG,
-        format='%(asctime)s %(levelname)s %(message)s',
-        filename=os.path.join(WCS_CACHE_DIR, logname),
-        filemode='w')
+    logger = logging.getLogger('wcs-dynexport')
+    logger.setLevel(logging.DEBUG)
+    log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
+    log_handler = logging.FileHandler(os.path.join(WCS_CACHE_DIR, logname))
+    log_handler.setLevel(logging.DEBUG)
+    log_handler.setFormatter(log_formatter)
+    logger.addHandler(log_handler)
 
-    logging.info('Début.')
+    logger.info('Début.')
+    log_handler.flush()
 
     set_wcs_publisher(domain)
     from wcs.formdef import FormDef
@@ -230,7 +252,7 @@ def get_wcs_form_data(domain, form):
     liste_attachements = {}
     for object in formdef.data_class().select():
         if object.user is None:
-            logging.warning("Dossier '%s' sans utilisateur associé ?!?"\
+            logger.warning("Dossier '%s' sans utilisateur associé ?!?"\
                             " On ignore...", object.id)
             continue
 
@@ -253,7 +275,10 @@ def get_wcs_form_data(domain, form):
         if object.evolution is not None:
             for e in object.evolution:
                 if e.comment is not None:
-                    who = pub.user_class.get(e.who).display_name
+                    try:
+                        who = pub.user_class.get(e.who).display_name
+                    except:
+                        who = 'Inconnu(e)'
                     e_time = time.strftime('%Y-%m-%d %H:%M:%S', e.time)
                     comment = '%s -- %s %s' % (e.comment, who, e_time)
                     result['wcs_comments'].append(comment)
@@ -267,11 +292,31 @@ def get_wcs_form_data(domain, form):
                 continue
             field_name = fields[field_id]['name']
             data = object.data.get(field_id)
+            # paliatif aux corrections de formulaires en cours de route
+            # (compensation nécessaire pour l'import depuis Sigma 2)
+            if data is None and field.required:
+                if isinstance(field, StringField) \
+                or isinstance(field, TextField) \
+                or isinstance(field, EmailField) \
+                or isinstance(field, ItemField):
+                    result[field_name] = '(vide)'
+                elif isinstance(field, ItemsField) \
+                  or isinstance(field, TableField):
+                    result[field_name] = '(vide)'
+                elif isinstance(field, BoolField):
+                    result[field_name] = False
+                elif isinstance(field, DateField):
+                    result[field_name] = "9999-12-31"
+                continue
             if data is None:
                 result[field_name] = None
                 continue
             if isinstance(field, StringField) or isinstance(field, TextField) \
             or isinstance(field, EmailField) or isinstance(field, ItemField):
+                # nettoyage du nom d'établissement (suppression id et Nord/Sud)
+                #m = match(ETABLISSEMENT_FORMAT, data)
+                #if m is not None:
+                #    data = m.groups()[0]
                 result[field_name] = data
             elif isinstance(field, ItemsField) or isinstance(field, TableField):
                 result[field_name] = data # liste => peux-être joindre sur ';'
@@ -293,7 +338,7 @@ def get_wcs_form_data(domain, form):
                         m = magicmime.file(p).split()[0].strip(';')
                         extension = mimetypes.guess_extension(m)
                     except:
-                        logging.warning("Type de fichier inconnu pour '%s'.", p)
+                        logger.warning("Type de fichier inconnu pour '%s'.", p)
                         extension = None
                     if extension is not None:
                         extension = extension[1:]
@@ -302,7 +347,7 @@ def get_wcs_form_data(domain, form):
                 result[field_name] = "%s.%s" % (field_name, extension)
                 qfiles[field_name] = data.qfilename
             else:
-                logging.warning("Type de champ inconnu '%s' pour '%s' (%s).",
+                logger.warning("Type de champ inconnu '%s' pour '%s' (%s).",
                             field.__class__.__name__, field_name, field.label)
 
         num_dossier = result['num_dossier']
@@ -325,7 +370,7 @@ def get_wcs_form_data(domain, form):
         data = json.dumps(result, ensure_ascii=False).encode('utf-8')
         set_wcs_cache(domain, form, 'data_%s.json' % filename, data)
 
-        logging.info("Dossier '%s' : %s.",
+        logger.info("Dossier '%s' : %s.",
                                     filename, result['wcs_workflow_status'])
 
     data = json.dumps(liste_attachements, ensure_ascii=False).encode('utf-8')
@@ -337,7 +382,8 @@ def get_wcs_form_data(domain, form):
     set_wcs_cache(domain, form, 'liste-dossiers.json', data)
     metadata.update({'dossiers': liste_dossiers})
 
-    logging.info('Fin.')
+    logger.info('Fin.')
+    log_handler.flush()
 
     data = json.dumps(metadata, ensure_ascii=False).encode('utf-8')
     set_wcs_cache(domain, form, 'metadata.json', data)
@@ -346,7 +392,7 @@ def get_wcs_form_data(domain, form):
 #    try:
 #        extract_data(formdef, OUTPUT_DIRECTORY)
 #    except:
-#        logging.exception("Interruption du traitement pour cause d'erreur !")
+#        logger.exception("Interruption du traitement pour cause d'erreur !")
 
 #--------------------------------------------------------------------------
 # gestion des requêtes web