Endpoints to search an address (Fantoir/Rivoli) #8
9 changed files with 124 additions and 5 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__
|
||||||
|
/elig-test.ini
|
0
address_finder/__init__.py
Normal file
0
address_finder/__init__.py
Normal file
71
address_finder/api.py
Normal file
71
address_finder/api.py
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from .model import Commune,FantoirVoie
|
||||||
|
|
||||||
|
# DB with addresses info
|
||||||
|
DB_ADDRESSES_PATH_ENV="DB_ADDRESSES_PATH"
|
||||||
|
DB_ADDRESSES_DEFAULT_PATH="/etc/fantoir.sqlite"
|
||||||
|
|
||||||
|
# Table for insee codes
|
||||||
|
DB_TABLE_INSEE_NAME="insee"
|
||||||
|
DB_COL_COMMUNE_INSEE="Code_commune_INSEE"
|
||||||
|
DB_COL_COMMUNE_NAME="Nom_commune"
|
||||||
|
DB_COL_COMMUNE_POSTE="Code_postal"
|
||||||
|
|
||||||
|
# Table for Fantoir voies (code Rivoli)
|
||||||
|
DB_TABLE_FANTOIR_NAME="keyv"
|
||||||
|
DB_COL_FANTOIR_INSEE="key"
|
||||||
|
DB_FANTOIR_INSEE_KEY_SUFFIX="keyv:"
|
||||||
|
|
||||||
|
# Utility to find an address
|
||||||
|
class AddressFinder:
|
||||||
|
|
||||||
|
def __init__(self, db_addresses_sqlite_path: str):
|
||||||
|
self.dbPath = db_addresses_sqlite_path
|
||||||
|
print("DB addresses Path : " + self.dbPath)
|
||||||
|
|
||||||
|
def getCommunesFromNameOrZipJson(self, communeNameOrZip: str) -> list[Commune]:
|
||||||
|
con = sqlite3.connect(self.dbPath)
|
||||||
|
con.row_factory = sqlite3.Row
|
||||||
|
cur = con.cursor()
|
||||||
|
communes: list[Commune] = []
|
||||||
|
if communeNameOrZip is None:
|
||||||
|
cur.execute(f"SELECT * from \"{DB_TABLE_INSEE_NAME}\"")
|
||||||
|
else:
|
||||||
|
cur.execute(f"SELECT * from \"{DB_TABLE_INSEE_NAME}\" WHERE {DB_COL_COMMUNE_NAME}=\"{communeNameOrZip}\" COLLATE nocase OR {DB_COL_COMMUNE_POSTE}=\"{communeNameOrZip}\"")
|
||||||
|
rows = [dict(row) for row in cur.fetchall()]
|
||||||
|
con.close()
|
||||||
|
for row in rows:
|
||||||
|
commune=Commune(
|
||||||
|
codeInsee=row[DB_COL_COMMUNE_INSEE],
|
||||||
|
nom=row[DB_COL_COMMUNE_NAME],
|
||||||
|
codeZip=row[DB_COL_COMMUNE_POSTE])
|
||||||
|
communes.append(commune)
|
||||||
|
return communes
|
||||||
|
|
||||||
|
def getCommuneFantoirVoiesJson(self, communeInseeCode: str) -> list[FantoirVoie]:
|
||||||
|
|
||||||
|
# Extract data from DB
|
||||||
|
con = sqlite3.connect(self.dbPath)
|
||||||
|
con.row_factory = sqlite3.Row
|
||||||
|
cur = con.cursor()
|
||||||
|
cur.execute(f"SELECT value from \"{DB_TABLE_FANTOIR_NAME}\" WHERE {DB_COL_FANTOIR_INSEE}=\"{DB_FANTOIR_INSEE_KEY_SUFFIX}{communeInseeCode}\"")
|
||||||
|
data_raw = cur.fetchone()
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
## Get JSON payload
|
||||||
|
|
||||||
|
fantoir_dict = []
|
||||||
|
# Check if data where found
|
||||||
|
if data_raw is not None:
|
||||||
|
data = dict(data_raw)
|
||||||
|
# Extract the data behind "value" which is a JSON structure
|
||||||
|
data_dict=json.loads(data.get("value"))
|
||||||
|
# In extracted JSON data, the interesting payload is behind "value" key
|
||||||
|
fantoir_dict = data_dict.get("value")
|
||||||
|
else:
|
||||||
|
print("Did not found any data matching Insee code " + str(communeInseeCode))
|
||||||
|
|
||||||
|
# Return the json dump
|
||||||
|
return fantoir_dict
|
17
address_finder/model.py
Normal file
17
address_finder/model.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
class Commune(TypedDict):
|
||||||
|
codeInsee: str
|
||||||
|
nom: str
|
||||||
|
codeZip: str
|
||||||
|
|
||||||
|
class FantoirVoie(TypedDict):
|
||||||
|
id: str
|
||||||
|
dateAjout: int
|
||||||
|
libelle: list[str]
|
||||||
|
typeVoie:str
|
||||||
|
codeCommune: str
|
||||||
|
codeFantoir: str
|
||||||
|
cleRivoli: str
|
||||||
|
nomCommune: str
|
||||||
|
predecesseur: bool
|
0
config/__init__.py
Normal file
0
config/__init__.py
Normal file
|
@ -2,10 +2,11 @@ import configparser
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
def __init__(self, username, password, source_addr):
|
def __init__(self, username, password, source_addr, db_addresses_sqlite_path):
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
self.source_addr = source_addr
|
self.source_addr = source_addr
|
||||||
|
self.db_addresses_sqlite_path = db_addresses_sqlite_path
|
||||||
self.debug = False
|
self.debug = False
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,4 +17,5 @@ def parse_config(cfgPath):
|
||||||
username = cfg.get("API", "username")
|
username = cfg.get("API", "username")
|
||||||
passwd = cfg.get("API", "password")
|
passwd = cfg.get("API", "password")
|
||||||
source_addr = cfg.get("API", "source_addr")
|
source_addr = cfg.get("API", "source_addr")
|
||||||
return Config(username, passwd, source_addr)
|
db_addresses_sqlite_path = cfg.get("ADDRESSES","db_addresses_sqlite_path")
|
||||||
|
return Config(username, passwd, source_addr,db_addresses_sqlite_path)
|
|
@ -3,4 +3,6 @@
|
||||||
password = xxx
|
password = xxx
|
||||||
# Whitelisted IP address from axione
|
# Whitelisted IP address from axione
|
||||||
# to send the requests from.
|
# to send the requests from.
|
||||||
source_addr = xxx.xxx.xxx.xxx
|
source_addr = xxx.xxx.xxx.xxx
|
||||||
|
[ADDRESSES]
|
||||||
|
db_addresses_sqlite_path = path/to/db.sqlite
|
|
@ -1,3 +1,3 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
DEBUG=true CONFIG=./elig-test.ini.sample FLASK_APP=webapp poetry run flask run --reload
|
DEBUG=true CONFIG=./elig-test.ini FLASK_APP=webapp poetry run flask run --reload
|
||||||
|
|
27
webapp.py
27
webapp.py
|
@ -1,8 +1,10 @@
|
||||||
import os
|
import os
|
||||||
from flask import Flask, render_template, request, escape
|
from flask import Flask, render_template, request, escape
|
||||||
|
import json
|
||||||
|
|
||||||
from axione_api.config import parse_config
|
from config.config import parse_config
|
||||||
from axione_api.api import query_axione_pto, parse_response
|
from axione_api.api import query_axione_pto, parse_response
|
||||||
|
from address_finder.api import AddressFinder
|
||||||
|
|
||||||
def load_config():
|
def load_config():
|
||||||
cfg_path = os.environ.get("CONFIG", "/etc/ftth-elig/conf.ini")
|
cfg_path = os.environ.get("CONFIG", "/etc/ftth-elig/conf.ini")
|
||||||
|
@ -19,6 +21,9 @@ def load_config():
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
cfg = load_config()
|
cfg = load_config()
|
||||||
|
|
||||||
|
addressFinder = AddressFinder(cfg.db_addresses_sqlite_path)
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@app.route("/", methods=['GET'])
|
@app.route("/", methods=['GET'])
|
||||||
|
@ -30,3 +35,23 @@ def show_result():
|
||||||
pto = escape(request.form['pto'])
|
pto = escape(request.form['pto'])
|
||||||
result = parse_response(query_axione_pto(cfg, pto))
|
result = parse_response(query_axione_pto(cfg, pto))
|
||||||
return render_template("result.html", pto=pto, result=result)
|
return render_template("result.html", pto=pto, result=result)
|
||||||
|
|
||||||
|
@app.route("/addresses/communes", methods=['GET'])
|
||||||
|
def get_communes():
|
||||||
|
to_search=request.args.get('s')
|
||||||
|
print(to_search)
|
||||||
|
communes=addressFinder.getCommunesFromNameOrZipJson(to_search)
|
||||||
|
response = app.response_class(
|
||||||
|
response=json.dumps(communes),
|
||||||
|
mimetype='application/json'
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@app.route("/addresses/fantoirvoies/<codeInsee>", methods=['GET'])
|
||||||
|
def get_fantoir_voies(codeInsee):
|
||||||
|
fantoirVoies=addressFinder.getCommuneFantoirVoiesJson(codeInsee)
|
||||||
|
response = app.response_class(
|
||||||
|
response=json.dumps(fantoirVoies),
|
||||||
|
mimetype='application/json'
|
||||||
|
)
|
||||||
|
return response
|
Loading…
Reference in a new issue