From a99de3a8597829b1be635c93a858b2bd3225e55b Mon Sep 17 00:00:00 2001 From: W1CDN Date: Sat, 13 May 2023 11:09:41 -0500 Subject: [PATCH] Allow query on any field in the packets table. --- api_app.py | 73 +++++++++++++++++++++++++++++++++++++++++++----- requirements.txt | 2 ++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/api_app.py b/api_app.py index 4f64710..c854482 100644 --- a/api_app.py +++ b/api_app.py @@ -10,6 +10,55 @@ import sqlite3 api_app = Flask(__name__) api = Api(api_app) +# TODO this is duplicated from kiss_and_db.py, can I avoid that? +db_fields = ("id", +"addresse", +"alive", +"altitude", +"comment", +"course", +"created", +"format", +"frame", +"from", +"gpsfixstatus", +"latitude", +"longitude", +"mbits", +"messagecapable", +"message_text", +"msgNo", +"mtype", +"object_format", +"object_name", +"path", +"phg", +"phg_dir", +"phg_gain", +"phg_height", +"phg_power", +"phg_range", +"posambiguity", +"raw", +"raw_timestamp", +"speed", +"station_call", +"station_lat", +"station_lon", +"status", +"subpacket", +"symbol", +"symbol_table", +"telemetry", +"timestamp", +"to", +"tEQNS", +"tPARM", +"tUNIT", +"via", +"weather", +"wx_raw_timestamp") + def read_config(): config = configparser.ConfigParser() config.read('config.ini') @@ -65,12 +114,22 @@ def select_all_frames(conn): rows = cur.fetchall() return rows -def select_frames(conn, n, from_): +def select_frames(conn, n, from_, url_params): + + # Should pass this a dict of fields and values (request.args) + # TODO clean data before sending to DB + # Filter out any keys that don't match db fields + # From https://stackoverflow.com/a/20256491 + dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ]) + field_where = dictfilt(url_params, db_fields) + # Then loop through fields to create query parts + # From https://stackoverflow.com/a/73512269/2152245 + field_where_str = ' AND '.join([f'"{k}" = \'{v}\'' for k,v in field_where.items()]) + cur = conn.cursor() # Workaround to deal with missing value in WHERE - from_ = "IS NOT NULL" if from_ == None else "='"+from_+"'" - #sql = "SELECT * FROM frames LIMIT "+n - sql = 'SELECT * FROM frames WHERE "from" {from_} ORDER BY created DESC LIMIT {n}'.format(from_=from_, n=n) + field_where_query = "" if field_where_str == "" else "WHERE "+field_where_str + sql = 'SELECT * FROM frames {field_where_query} ORDER BY created DESC LIMIT {n}'.format(field_where_query=field_where_query, n=n) print(sql) cur.execute(sql) rows = cur.fetchall() @@ -87,7 +146,7 @@ class Packets(Resource): conn = get_db_connection() # Limit to number of records requested - data = select_frames(conn, n = n, from_ = from_) + data = select_frames(conn, n = n, from_ = from_, url_params = request.args.to_dict()) # Sort by created date, descending (https://stackoverflow.com/a/45266808) #data.sort(key=operator.itemgetter('created'), reverse=True) return {'data': data}, 200 # return data and 200 OK code @@ -97,8 +156,8 @@ config = read_config() log_folder = config['Settings']['log_folder'] # Start subprocess to watch KISS connection -import subprocess -subprocess.Popen(["python3","kiss_and_db.py"]) +#import subprocess +#subprocess.Popen(["python3","kiss_and_db.py"]) api.add_resource(Packets, '/packets') # and '/locations' is our entry point for Locations diff --git a/requirements.txt b/requirements.txt index 85407aa..13524b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ flask flask_restful aprs aprslib +sqlite3 +json