Endpoints to find a Fantoir address

This commit is contained in:
Johan Le Baut 2021-11-02 15:21:34 +01:00
parent f53d5b6373
commit 6e2899a91b
9 changed files with 124 additions and 5 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__
/elig-test.ini

View file

71
address_finder/api.py Normal file
View 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
View 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
View file

View 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)

View file

@ -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

View file

@ -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

View file

@ -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