11"""Query alert information from AeroAPI and present it to a frontend service"""
22import os
3- from datetime import timezone
3+ from datetime import datetime
44from typing import Dict , Any , Union
55
66import json
77import requests
88from flask import Flask , jsonify , Response , request
99from flask_cors import CORS
1010
11- from sqlalchemy import exc , create_engine , MetaData , Table , Column , Integer , String , insert
11+ from sqlalchemy import (exc , create_engine , MetaData , Table ,
12+ Column , Integer , Boolean , Text , insert , Date )
1213
1314AEROAPI_BASE_URL = "https://aeroapi.flightaware.com/aeroapi"
1415AEROAPI_KEY = os .environ ["AEROAPI_KEY" ]
2425 "sqlite+pysqlite:////var/db/aeroapi_alerts/aeroapi_alerts.db" , echo = False , future = True
2526)
2627
28+ # Define table and metadata to insert and create
29+ metadata_obj = MetaData ()
30+ aeroapi_alert_configurations = Table (
31+ "aeroapi_alert_configurations" ,
32+ metadata_obj ,
33+ Column ("fa_alert_id" , Integer , primary_key = True ),
34+ Column ("ident" , Text ),
35+ Column ("origin" , Text ),
36+ Column ("destination" , Text ),
37+ Column ("aircraft_type" , Text ),
38+ Column ("start_date" , Date ),
39+ Column ("end_date" , Date ),
40+ Column ("max_weekly" , Integer ),
41+ Column ("eta" , Integer ),
42+ Column ("arrival" , Boolean ),
43+ Column ("cancelled" , Boolean ),
44+ Column ("departure" , Boolean ),
45+ Column ("diverted" , Boolean ),
46+ Column ("filed" , Boolean ),
47+ )
48+
2749
28- def insert_into_db (data_to_insert : Dict [str , Union [str , int ]]) -> int :
50+ def create_table ():
51+ """
52+ Check if the tables exist, and if they don't create them.
53+ Returns None, raises exception if error
54+ """
55+ try :
56+ # Create the table if it doesn't exist
57+ metadata_obj .create_all (engine )
58+ app .logger .info ("Table successfully created (if not already created)" )
59+ except exc .SQLAlchemyError as e :
60+ # Since creation of table is a critical error, raise exception
61+ app .logger .error (f"SQL error occurred during creation of table (CRITICAL - THROWING ERROR): { e } " )
62+ raise e
63+
64+
65+ def insert_into_db (data_to_insert : Dict [str , Union [str , int , bool ]]) -> int :
2966 """
3067 Insert object into the database based off of the engine.
3168 Assumes data_to_insert has values for all the keys:
3269 fa_alert_id, ident, origin, destination, aircraft_type, start_date, end_date.
3370 Returns 0 on success, -1 otherwise
3471 """
35- table_name = "aeroapi_alerts_table"
3672 try :
37- metadata_obj = MetaData ()
38- # create the table if it doesn't exist
39- table_to_insert = Table (
40- table_name ,
41- metadata_obj ,
42- Column ("fa_alert_id" , Integer , primary_key = True ),
43- Column ("ident" , String (30 )),
44- Column ("origin" , String (30 )),
45- Column ("destination" , String (30 )),
46- Column ("aircraft_type" , String (30 )),
47- Column ("start_date" , String (30 )),
48- Column ("end_date" , String (30 )),
49- )
50- table_to_insert .create (engine , checkfirst = True )
51-
52- # insert the info given
5373 with engine .connect () as conn :
54- stmt = insert (table_to_insert )
74+ stmt = insert (aeroapi_alert_configurations )
5575 conn .execute (stmt , data_to_insert )
5676 conn .commit ()
5777
78+ app .logger .info ("Data successfully inserted into table" )
79+
5880 except exc .SQLAlchemyError as e :
59- app .logger .error (f"SQL error occurred: { e } " )
81+ app .logger .error (f"SQL error occurred during insertion into table : { e } " )
6082 return - 1
6183
6284 return 0
@@ -111,12 +133,20 @@ def create_alert() -> Response:
111133 # Package created alert and put into database
112134 fa_alert_id = int (result .headers ["Location" ][8 :])
113135 r_alert_id = fa_alert_id
136+ # Flatten events to insert into database
137+ data ["arrival" ] = data ["events" ]["arrival" ]
138+ data ["departure" ] = data ["events" ]["departure" ]
139+ data ["cancelled" ] = data ["events" ]["cancelled" ]
140+ data ["diverted" ] = data ["events" ]["diverted" ]
141+ data ["filed" ] = data ["events" ]["filed" ]
114142 data .pop ("events" )
115143 data .pop ("max_weekly" )
116- # rename dates to avoid sql keyword "end" issue
117- # default to None in case a user directly submits an incomplete payload
144+ # Rename dates to avoid sql keyword "end" issue, and also change to Python datetime.datetime()
145+ # Default to None in case a user directly submits an incomplete payload
118146 data ["start_date" ] = data .pop ("start" , None )
119147 data ["end_date" ] = data .pop ("end" , None )
148+ data ["start_date" ] = datetime .strptime (data ["start_date" ], "%Y-%m-%d" )
149+ data ["end_date" ] = datetime .strptime (data ["end_date" ], "%Y-%m-%d" )
120150 data ["fa_alert_id" ] = fa_alert_id
121151
122152 if insert_into_db (data ) == - 1 :
@@ -128,4 +158,7 @@ def create_alert() -> Response:
128158 return jsonify ({"Alert_id" : r_alert_id , "Success" : r_success , "Description" : r_description })
129159
130160
131- app .run (host = "0.0.0.0" , port = 5000 , debug = True )
161+ if __name__ == "__main__" :
162+ # Create the table if it wasn't created before startup
163+ create_table ()
164+ app .run (host = "0.0.0.0" , port = 5000 , debug = True )
0 commit comments