""" Importe les données géographiques des essais de compactage depuis les fichiers Shapefile recus des exploitants vers la base Postgis de ControlesSig - Ajoute de nouveaux chantiers / points de compactage à la base POSTGIS - Les chantiers créés sont issus des dossiers du répertoire 'compactage_dir' - Une fois importés, ces dossiers sont renommés 'XXXXXX' > 'I_XXXXXX' - Les noms complets des chantiers sont récupérés dans la base Controles Pour lancer l'import de tous les chantiers (pas de prompt pour la selection), utilisez l'option --all Pour répondre automatiquement à la demande "Voulez-vous remplacer le chantier existant", utilisez les options --yes ou --no @author: olivier.massot, mai 2018 """ import logging import re import sys from path import Path import shapefile from core import logconf from core.pde import ControlesDb, CSigDb, COMPACTAGE_DIR, QGisChantier, \ QGisPoint, SRID logger = logging.getLogger("qgis_sync_compactage") logconf.start("qgis_sync_compactage", logging.DEBUG) # # POUR TESTER, décommenter les lignes suivantes ##----------------------------------------------- ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb") CSigDb.server = "TR-POSTGIS-02" CSigDb.pwd = "Am5VOMkdFHU7WwrfVOs9" COMPACTAGE_DIR = Path(__file__).parent / "resources" / "test_qgis_sync_compactage" logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)] logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>") ##----------------------------------------------- def main(): # Connexion à ControlesSig (postgres) csig_db = CSigDb(autocommit=False) # Connexion à Controles controles_db = ControlesDb(autocommit=False) # Regex pour parser les noms de repertoires rxi = re.compile(r"^(\d{5,6})([-_]S?\d*)?[\s_]?(.*)$") # non importés a_importer = [subdir for subdir in COMPACTAGE_DIR.dirs() if rxi.search(subdir.name)] if a_importer and not "--all" in sys.argv: reponse = input("""Les chantiers suivants peuvent être importés. Tapez les numéros correpsondant aux chantiers à importer, séparés par une virgule (ou * pour tout importer) Ex: "1", "1,2,5", "*" {}""".format("\n".join(["{} - {}".format(i, item.name) for i, item in enumerate(a_importer)]))) if reponse != "*": a_importer = [item for i, item in enumerate(a_importer) if str(i) in reponse.split(",")] if not a_importer: logger.info("Aucun nouveau dossier à importer") sys.exit() chantiers = [] # ** Read the data in the shapefiles and store it in memory ** for chantier_dir_path in a_importer: logger.info("Lecture de : %s", chantier_dir_path) # instanciate a new Chantier chantier = QGisChantier() chantier.dir_path = chantier_dir_path logger.debug("> parse path") parsed = rxi.search(chantier_dir_path.name) chantier.number = parsed.group(1) chantier.complement = parsed.group(2).replace("_", "-") if parsed.group(2) else "" logger.debug("> number: %s, compl: %s", chantier.number, chantier.complement) # query for name in ControlesDb logger.debug("> Query ControlesDb for chantier's name") row = controles_db.first("""SELECT tblChantiers.lngChantierId, tblCollectivites.strNom FROM tblChantiers INNER JOIN tblCollectivites ON tblChantiers.strCollectiviteId = tblCollectivites.strCollectiviteId WHERE lngChantierId = {lngChantierId};""".format(lngChantierId=chantier.number)) chantier.name = "{}{} {}".format(chantier.number, chantier.complement, row.strNom) logger.debug("> {}".format(chantier.name)) # importe le fichier shape dans une couche temp shp_path = chantier_dir_path / "{}_p_PointCompactage.shp".format(chantier_dir_path.name) logger.debug("Read the shapefile: %s", shp_path) sf = shapefile.Reader(shp_path) # should we check? : if sf.shapeType != 1: logger.error("Le fichier shapefile n'est pas de type POINT") sys.exit(1) sh_points = sf.shapeRecords() if not sh_points: logger.error("Le fichier shapefile ne contient aucune donnees") sys.exit(1) chantier.points = [] for sh_point in sh_points: # create the Point instance point = QGisPoint() point.number = sh_point.record[0] point.name = sh_point.record[1] point.x, point.y = sh_point.shape.points[0] logger.debug("> {}".format(point)) chantier.points.append(point) del sf, sh_points # compute the chantier's rect coordinates logger.debug("Compute the chantier's rect coordinates") chantier.x0 = min([point.x for point in chantier.points]) - 5 chantier.x1 = max([point.x for point in chantier.points]) + 5 chantier.y0 = min([point.y for point in chantier.points]) - 5 chantier.y1 = max([point.y for point in chantier.points]) + 5 logger.debug("> ({}, {}, {}, {})".format(chantier.x0, chantier.x1, chantier.y0, chantier.y1)) chantiers.append(chantier) # ** Insère les chantiers dans la base ** for chantier in chantiers: logger.debug("** Chantier {}: {} points".format(chantier.name, len(chantier.points))) # Contrôle si un chantier de compactage portant ce nom n'existe pas déjà dans la base qry = csig_db.read(u"SELECT id FROM t_chantiers WHERE nom = '{}' AND id_type_chantier=2;".format(chantier.name)) cancelled = False for row in qry: logger.warning("Un chantier de compactage portant ce nom existe déjà '{}' (id {})".format(chantier.name, row.id)) if not "--no" in sys.argv and ("--yes" in sys.argv or input("Voulez-vous le remplacer? (o/n)") == "o"): # delete the old chantier csig_db.execute("""DELETE FROM t_points_compactage WHERE id_chantier = {};""".format(row.id)) csig_db.execute("""DELETE FROM t_chantiers WHERE id = {};""".format(row.id)) logger.info("> L'ancien chantier a été supprimé".format(chantier.name, row.id)) else: cancelled = True break if cancelled: logger.warning("Import du chantier annulé") continue # Créé le chantier q = csig_db.first("""INSERT INTO t_chantiers(id_type_chantier, numero, nom, geom, archive) VALUES ({chantier_type}, {number}, '{name}', {geom}, {archive}) RETURNING id; """.format( chantier_type=2, number=chantier.number, name=chantier.name, geom="ST_GeomFromText('POLYGON(({x0} {y0}, \ {x0} {y1}, {x1} {y1}, {x1} {y0}, {x0} {y0}))', {srid})".format(x0=chantier.x0, x1=chantier.x1, y0=chantier.y0, y1=chantier.y1, srid=SRID), archive="FALSE" ) ) # get its postgis ID logger.debug("Getting newly created ID") chantier.pgid = q.id logger.debug("> {}".format(chantier.pgid)) q = None # create the points for point in chantier.points: csig_db.execute("""INSERT INTO t_points_compactage(numero, nom, id_chantier, geom, archive) VALUES ({number}, '{name}', {chantier_id}, ST_GeomFromText('POINT({x} {y})', {srid}), False); """.format( number=point.number, name=point.name, chantier_id=chantier.pgid, x=point.x, y=point.y, srid=SRID ) ) csig_db.commit() # rename the directory to mark it as imported ('I_') new_path = r"{}\I_{}".format(chantier.dir_path.parent, chantier.dir_path.name) logger.debug("Rename {} to {}".format(chantier.dir_path, new_path)) try: chantier.dir_path.rename(new_path) except: logger.error("Impossible de renommer le dossier") logger.info("Le chantier %s a été importé", chantier.name) csig_db.close() controles_db.close() if __name__ == "__main__": main() logger.info("-- Fin --")