ajout connexion Liazo
This commit is contained in:
parent
b05cf14bf3
commit
b9df2de12a
9 changed files with 263 additions and 147 deletions
|
@ -1,2 +1,2 @@
|
||||||
[DB]
|
[DB]
|
||||||
path = /path/to/ipe.sqlite
|
axione_ipe_path = /path/to/ipe.sqlite
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .axione import *
|
||||||
|
from .liazo import *
|
|
@ -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")
|
||||||
|
|
41
webapp/ipe_fetcher/liazo.py
Normal file
41
webapp/ipe_fetcher/liazo.py
Normal 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
|
|
@ -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
|
||||||
|
|
1
webapp/ipe_fetcher/sqlite_connector/__init__.py
Normal file
1
webapp/ipe_fetcher/sqlite_connector/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# from .cursor import *
|
8
webapp/ipe_fetcher/sqlite_connector/cursor.py
Normal file
8
webapp/ipe_fetcher/sqlite_connector/cursor.py
Normal 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
|
|
@ -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
|
|
||||||
|
|
|
@ -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}¢erlat=${mc.lat}¢erlng=${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);
|
||||||
|
|
Loading…
Reference in a new issue