ajout connexion Liazo

This commit is contained in:
Johan Le Baut 2022-03-23 22:54:04 +01:00
parent b05cf14bf3
commit b9df2de12a
9 changed files with 263 additions and 147 deletions

View file

@ -1,2 +1,2 @@
[DB] [DB]
path = /path/to/ipe.sqlite axione_ipe_path = /path/to/ipe.sqlite

View file

@ -0,0 +1,2 @@
from .axione import *
from .liazo import *

View file

@ -1,8 +1,86 @@
# const AXIONE_ETAT_DEPLOYE = from ipe_fetcher.model import AreaCoordinates, Building, FAIEligibilityStatus
# "DEPLOYE" from ipe_fetcher.sqlite_connector.cursor import getCursorWithSpatialite
# const AXIONE_ETAT_DEPLOIEMENT = "EN COURS DE DEPLOIEMENT" from os.path import exists
# const AXIONE_ETAT_ABANDONNE = "ABANDONNE"
# const AXIONE_ETAT_CIBLE = "CIBLE" AXIONE_ETAT_DEPLOYE = "DEPLOYE"
# const AXIONE_ETAT_SIGNE = "SIGNE" AXIONE_ETAT_DEPLOIEMENT = "EN COURS DE DEPLOIEMENT"
# const AXIONE_ETAT_RAD_DEPLOIEMENT = "RAD EN COURS DE DEPLOIEMENT" AXIONE_ETAT_ABANDONNE = "ABANDONNE"
# const AXIONE_ETAT_RACCORDABLE_DEMANDE = "RACCORDABLE DEMANDE" AXIONE_ETAT_CIBLE = "CIBLE"
AXIONE_ETAT_SIGNE = "SIGNE"
AXIONE_ETAT_RAD_DEPLOIEMENT = "RAD EN COURS DE DEPLOIEMENT"
AXIONE_ETAT_RACCORDABLE_DEMANDE = "RACCORDABLE DEMANDE"
class Axione:
def __init__(self, db_axione_ipe_path: str):
self.db_axione_ipe_path = db_axione_ipe_path
# Check at least that the file exists
if not exists(self.db_axione_ipe_path):
raise ValueError(f"File {self.db_axione_ipe_path} does not exist")
def getAreaBuildings(
self, areaCoordinates: AreaCoordinates, existing_buildings: dict
) -> dict:
cur = None
# Try to get cursor on Axone database
try:
cur = getCursorWithSpatialite(self.db_axione_ipe_path)
except Exception as err:
print("Error while connecting to DB: ", err)
raise "Could not get Axione data"
# Let's first see how big is the area we're about to query.
# If it's too big, abort the request to prevent a server DOS.
cur.execute(
"""
SELECT Area(BuildMBR(:swx,:swy,:nex,:ney,4326))
""",
areaCoordinates,
)
req_area = cur.fetchone()[0]
if req_area <= 0.08:
cur.execute(
"""
SELECT
X(ImmeubleGeoPoint),
Y(ImmeubleGeoPoint),
IdentifiantImmeuble,
EtatImmeuble,
NumeroVoieImmeuble,
TypeVoieImmeuble,
NomVoieImmeuble
FROM ipe
WHERE ROWID IN (
SELECT ROWID FROM SpatialIndex
WHERE f_table_name = 'ipe' AND
search_frame = BuildMBR(:swx, :swy, :nex, :ney, 4326))
""",
areaCoordinates,
)
if not existing_buildings:
existing_buildings = dict()
buildings = existing_buildings
for b in cur.fetchall():
etatImm = b[3]
idImm = b[2]
isEligible = etatImm == AXIONE_ETAT_DEPLOYE
aquilenetEligStatus = FAIEligibilityStatus(
isEligible=isEligible,
ftthStatus=etatImm,
reasonNotEligible=None if isEligible else "Pas encore deploye",
)
if buildings.get(idImm):
buildings[idImm]["aquilenetEligStatus"] = aquilenetEligStatus
else:
building = Building(
x=b[0],
y=b[1],
idImm=idImm,
numVoieImm=b[4],
typeVoieImm=b[5],
nomVoieImm=b[6],
aquilenetEligStatus=aquilenetEligStatus,
)
buildings[idImm] = building
return buildings
else:
raise ValueError("The requested area is too wide, please reduce it")

View file

@ -0,0 +1,41 @@
import http.client as httplib
from ipe_fetcher.model import AreaCoordinates, Building, FAIEligibilityStatus
import json
class Liazo:
def __init__(self):
self.https_conn = httplib.HTTPSConnection("vador.fdn.fr")
def getAreaBuildings(
self, center_lat: float, center_lng: float, existing_buildings: dict
) -> dict:
c = self.https_conn
req = "/souscription/gps-batiments.cgi?etape=gps_batiments&lat1=%f&lat2=%f&lon1=%f&lon2=%f" % (center_lat-0.0011, center_lat+0.0011, center_lng-0.0022, center_lng+0.0022)
req = req.replace(" ", "%20")
print("Req FDN with: ", req)
c.request("GET", req)
r = c.getresponse()
if r.status < 200 or r.status >= 300:
print("Erreur de serveur chez FDN. Merci de nous faire remonter le numéro de téléphone qui provoque cette erreur")
return
d = r.read()
c.close()
v = json.loads(d.decode("utf-8"))
if not existing_buildings:
existing_buildings = dict()
buildings = existing_buildings
for building in v:
idImm=building.get('ref')
if not buildings.get(idImm):
building = Building(
y=building.get('lat'),
x=building.get('lon'),
idImm=idImm,
numVoieImm="",
typeVoieImm="",
nomVoieImm=""
)
print("add building ", building)
buildings[idImm] = building
return buildings

View file

@ -3,7 +3,6 @@ from typing import TypedDict
class FAIEligibilityStatus(TypedDict): class FAIEligibilityStatus(TypedDict):
isEligible: bool isEligible: bool
ftthDeployer: str
ftthStatus: str ftthStatus: str
reasonNotEligible: str reasonNotEligible: str
@ -18,3 +17,10 @@ class Building(TypedDict):
aquilenetEligStatus: FAIEligibilityStatus aquilenetEligStatus: FAIEligibilityStatus
ffdnEligStatus: FAIEligibilityStatus ffdnEligStatus: FAIEligibilityStatus
othersEligStatus: FAIEligibilityStatus othersEligStatus: FAIEligibilityStatus
class AreaCoordinates(TypedDict):
swx: float
swy: float
nex: float
ney: float

View file

@ -0,0 +1 @@
# from .cursor import *

View file

@ -0,0 +1,8 @@
import sqlite3
def getCursorWithSpatialite(db_path: str = None) -> sqlite3.Cursor:
db = sqlite3.connect(db_path)
cur = db.cursor()
db.enable_load_extension(True)
cur.execute('SELECT load_extension("mod_spatialite")')
return cur

View file

@ -4,30 +4,37 @@ from typing import TypedDict
import configparser import configparser
import sqlite3 import sqlite3
import os import os
from ipe_fetcher import Liazo,Axione
class Config(TypedDict): class Config(TypedDict):
dbPath: str axione_ipe_path: str
def parseConfig() -> Config: def parseConfig() -> Config:
cfg_path = os.environ.get("CONFIG", "/etc/ftth-ipe-map/conf.ini") cfg_path = os.environ.get("CONFIG", "/etc/ftth-ipe-map/conf.ini")
cfg = configparser.ConfigParser() cfg = configparser.ConfigParser()
with open(cfg_path, "r") as f: with open(cfg_path, "r") as f:
cfg.read_file(f) cfg.read_file(f)
return {'dbPath':cfg.get("DB","path")} return {"axione_ipe_path": cfg.get("DB", "axione_ipe_path")}
app = Flask(__name__) app = Flask(__name__)
cfg: Config = parseConfig() cfg: Config = parseConfig()
axione = Axione(cfg.get("axione_ipe_path"))
liazo = Liazo()
@app.route("/", methods=["GET"]) @app.route("/", methods=["GET"])
def getMap(): def getMap():
return render_template("map.html") return render_template("map.html")
@app.route("/eligdata", methods=["GET"]) @app.route("/eligdata", methods=["GET"])
def getEligData(): def getEligData():
args = request.args args = request.args
valid_args = True valid_args = True
processed_args = {} processed_args = {}
for k in ['swx', 'swy', 'nex', 'ney']: for k in ["swx", "swy", "nex", "ney", "centerlat", "centerlng"]:
valid_args = valid_args and k in args valid_args = valid_args and k in args
if valid_args: if valid_args:
try: try:
@ -35,43 +42,14 @@ def getEligData():
except ValueError: except ValueError:
valid_args = False valid_args = False
if valid_args: if valid_args:
cur = cursorWithSpatialite() buildings = dict()
# Let's first see how big is the area we're about to query. try:
# If it's too big, abort the request to prevent a server DOS. buildings = axione.getAreaBuildings(processed_args, buildings)
cur.execute(''' except ValueError as err:
SELECT Area(BuildMBR(:swx,:swy,:nex,:ney,4326)) print("Could not get Axione data for this area:", err)
''',processed_args)
req_area = cur.fetchone()[0] buildings = liazo.getAreaBuildings(processed_args["centerlat"], processed_args["centerlng"], buildings)
if req_area <= 0.08:
cur.execute('''
SELECT
X(ImmeubleGeoPoint),
Y(ImmeubleGeoPoint),
IdentifiantImmeuble,
EtatImmeuble,
NumeroVoieImmeuble,
TypeVoieImmeuble,
NomVoieImmeuble
FROM ipe
WHERE ROWID IN (
SELECT ROWID FROM SpatialIndex
WHERE f_table_name = 'ipe' AND
search_frame = BuildMBR(:swx, :swy, :nex, :ney, 4326))
''',processed_args)
buildings = [ {
'x':b[0], 'y':b[1], 'idImm':b[2],
'etatImm':b[3], 'numVoieImm': b[4],
'typeVoieImm': b[5], 'nomVoieImm': b[6]
} for b in cur.fetchall()]
return {"buildings": buildings} return {"buildings": buildings}
else:
return "The requested area is too wide, please reduce it", 400
else: else:
return "Invalid bounding box coordinates", 400 return "Invalid bounding box coordinates", 400
def cursorWithSpatialite():
db = sqlite3.connect(cfg['dbPath'])
cur = db.cursor()
db.enable_load_extension(True)
cur.execute('SELECT load_extension("mod_spatialite")')
return cur

View file

@ -68,7 +68,8 @@ function initAddrSearch(map) {
function updateEligData(map, eligData) { function updateEligData(map, eligData) {
markers.map(marker => map.removeLayer(marker)); markers.map(marker => map.removeLayer(marker));
let buildings = eligData.buildings; let buildings = eligData.buildings;
markers = buildings.map(building => { console.log(buildings)
markers = Object.values(buildings).map(building => {
const latlng = new L.latLng(building.y, building.x); const latlng = new L.latLng(building.y, building.x);
const addrImm = `${building.numVoieImm} ${building.typeVoieImm} ${building.nomVoieImm}` const addrImm = `${building.numVoieImm} ${building.typeVoieImm} ${building.nomVoieImm}`
const marker = new L.marker(latlng) const marker = new L.marker(latlng)
@ -86,10 +87,11 @@ function updateUrl(map) {
async function fetchEligData(map) { async function fetchEligData(map) {
const zoom = map.getZoom(); const zoom = map.getZoom();
if (zoom >= minZoomForRequest) { if (zoom >= minZoomForRequest) {
const mc = map.getCenter();
const bounds = map.getBounds(); const bounds = map.getBounds();
const sw = bounds.getSouthWest(); const sw = bounds.getSouthWest();
const ne = bounds.getNorthEast(); const ne = bounds.getNorthEast();
const reqUri = encodeURI(`eligdata?swx=${sw.lng}&swy=${sw.lat}&nex=${ne.lng}&ney=${ne.lat}`); const reqUri = encodeURI(`eligdata?swx=${sw.lng}&swy=${sw.lat}&nex=${ne.lng}&ney=${ne.lat}&centerlat=${mc.lat}&centerlng=${mc.lng}`);
const source = await fetch(reqUri); const source = await fetch(reqUri);
const eligData = await source.json(); const eligData = await source.json();
updateEligData(map, eligData); updateEligData(map, eligData);