From e1d649283907e6f81d8e5f5a21e0268735158aec Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 14 Jul 2022 03:16:03 +0000 Subject: [PATCH 01/10] Add Endpoint for Deleting Alert Configurations Add endpoint that takes alert configuration ID from the front end and makes a POST request to AeroAPI to delete it. BCK-7007 --- alerts_backend/python/app.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index 4e8a9f8..307a81a 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -123,6 +123,34 @@ def insert_into_table(data_to_insert: Dict[str, Any], table: Table) -> int: return 0 +@app.rout("/delete", methods=["POST"]) +def delete_alert(): + r_success: bool = False + r_description: str + # Process json + content_type = request.headers.get("Content-Type") + data: Dict[str, Any] + + if content_type != "application/json": + r_description = "Invalid content sent" + else: + data = request.json + api_resource = f"/alerts/{data['alert_id']}" + logger.info(f"Making AeroAPI request to POST {api_resource}") + result = AEROAPI.post(f"{AEROAPI_BASE_URL}{api_resource}", json=data) + if result.status_code != 204: + # return to front end the error, decode and clean the response + try: + processed_json = result.json() + r_description = f"Error code {result.status_code} with the following description: {processed_json['detail']}" + except json.decoder.JSONDecodeError: + r_description = f"Error code {result.status_code} could not be parsed into JSON. The following is the HTML response given: {result.text}" + else: + r_success = True + r_description = f"Request sent successfully, alert configuration {data['alert_id']} has been deleted" + return jsonify({"Success": r_success, "Description": r_description}) + + @app.route("/alert_configs") def get_alert_configs(): """ @@ -200,7 +228,7 @@ def create_alert() -> Response: # initialize response headers r_alert_id: int = -1 r_success: bool = False - r_description: str = "" + r_description: str # Process json content_type = request.headers.get("Content-Type") data: Dict[str, Any] From 14b0a2ded9910d06c1c2226aa36d1371d730f657 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 14 Jul 2022 17:02:26 +0000 Subject: [PATCH 02/10] Change POST to DELETE Minor change that changed AeroAPI post to delete BCK-7007 --- alerts_backend/python/app.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index 307a81a..ec2cfac 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -123,7 +123,7 @@ def insert_into_table(data_to_insert: Dict[str, Any], table: Table) -> int: return 0 -@app.rout("/delete", methods=["POST"]) +@app.route("/delete", methods=["POST"]) def delete_alert(): r_success: bool = False r_description: str @@ -137,7 +137,7 @@ def delete_alert(): data = request.json api_resource = f"/alerts/{data['alert_id']}" logger.info(f"Making AeroAPI request to POST {api_resource}") - result = AEROAPI.post(f"{AEROAPI_BASE_URL}{api_resource}", json=data) + result = AEROAPI.delete(f"{AEROAPI_BASE_URL}{api_resource}", json=data) if result.status_code != 204: # return to front end the error, decode and clean the response try: @@ -150,7 +150,7 @@ def delete_alert(): r_description = f"Request sent successfully, alert configuration {data['alert_id']} has been deleted" return jsonify({"Success": r_success, "Description": r_description}) - + @app.route("/alert_configs") def get_alert_configs(): """ @@ -292,4 +292,4 @@ def create_alert() -> Response: if __name__ == "__main__": # Create the table if it wasn't created before startup create_tables() - app.run(host="0.0.0.0", port=5000, debug=True) + app.run(host="0.0.0.0", port=5001, debug=True) From d4dfcd64ff2791cb3336adb3ec303ed5e37939b0 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 14 Jul 2022 19:40:09 +0000 Subject: [PATCH 03/10] Add SQL Function Add SQL function to delete the alert configuration from the SQL database and other small changes. BCK-7007 --- alerts_backend/python/app.py | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index ec2cfac..5a731c9 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -10,7 +10,8 @@ from flask_cors import CORS from sqlalchemy import (exc, create_engine, MetaData, Table, - Column, Integer, Boolean, Text, insert, Date, DateTime) + Column, Integer, Boolean, Text, insert, + Date, DateTime, delete) from sqlalchemy.sql import func from sqlalchemy import ( exc, @@ -123,6 +124,23 @@ def insert_into_table(data_to_insert: Dict[str, Any], table: Table) -> int: return 0 +def delete_from_table(fa_alert_id: int): + """ + Delete alert config from SQL Alert Configurations table based on FA Alert ID. + Returns 0 on success, -1 otherwise. + """ + try: + with engine.connect() as conn: + stmt = delete(aeroapi_alert_configurations).where(aeroapi_alert_configurations.c.fa_alert_id == fa_alert_id) + conn.execute(stmt) + conn.commit() + logger.info(f"Data successfully deleted from {aeroapi_alert_configurations.name}") + except exc.SQLAlchemyError as e: + logger.error(f"SQL error occurred during deletion from table {aeroapi_alert_configurations.name}: {e}") + return -1 + return 0 + + @app.route("/delete", methods=["POST"]) def delete_alert(): r_success: bool = False @@ -135,7 +153,8 @@ def delete_alert(): r_description = "Invalid content sent" else: data = request.json - api_resource = f"/alerts/{data['alert_id']}" + fa_alert_id = data['fa_alert_id'] + api_resource = f"/alerts/{fa_alert_id}" logger.info(f"Making AeroAPI request to POST {api_resource}") result = AEROAPI.delete(f"{AEROAPI_BASE_URL}{api_resource}", json=data) if result.status_code != 204: @@ -146,8 +165,13 @@ def delete_alert(): except json.decoder.JSONDecodeError: r_description = f"Error code {result.status_code} could not be parsed into JSON. The following is the HTML response given: {result.text}" else: - r_success = True - r_description = f"Request sent successfully, alert configuration {data['alert_id']} has been deleted" + # Check if data was inserted into database properly + if delete_from_table(fa_alert_id) == -1: + r_description = "Error deleting the alert configuration from the SQL Database" + else: + r_success = True + r_description = f"Request sent successfully, alert configuration {fa_alert_id} has been deleted" + return jsonify({"Success": r_success, "Description": r_description}) @@ -292,4 +316,4 @@ def create_alert() -> Response: if __name__ == "__main__": # Create the table if it wasn't created before startup create_tables() - app.run(host="0.0.0.0", port=5001, debug=True) + app.run(host="0.0.0.0", port=5000, debug=True) From 13e4ce8fff76b33756f40a920cee7c534567874c Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 14 Jul 2022 21:50:00 +0000 Subject: [PATCH 04/10] Logger Change Change it to DELETE instead of POST BCK-7007 --- alerts_backend/python/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index b0d6fc5..7f3ec06 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -155,7 +155,7 @@ def delete_alert(): data = request.json fa_alert_id = data['fa_alert_id'] api_resource = f"/alerts/{fa_alert_id}" - logger.info(f"Making AeroAPI request to POST {api_resource}") + logger.info(f"Making AeroAPI request to DELETE {api_resource}") result = AEROAPI.delete(f"{AEROAPI_BASE_URL}{api_resource}", json=data) if result.status_code != 204: # return to front end the error, decode and clean the response From 4c698216098d98051b8b2162513010ef8cc02d90 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Tue, 19 Jul 2022 21:27:31 +0000 Subject: [PATCH 05/10] Comment Change Add comment for the endpoint for deleting an alert. BCK-7007 --- alerts_backend/python/app.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index 7f3ec06..7d5cb36 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -143,6 +143,12 @@ def delete_from_table(fa_alert_id: int): @app.route("/delete", methods=["POST"]) def delete_alert(): + """ + Function to delete the alert given (with key "fa_alert_id" in the payload). + Deletes the given alert via AeroAPI DELETE call and then deletes it from the + SQLite database. Returns JSON Response in form {"Success": True/False, + "Description": } + """ r_success: bool = False r_description: str # Process json From e2794bbc5bd3962440d3a32db826a9ebc781043b Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 20 Jul 2022 21:34:05 +0000 Subject: [PATCH 06/10] Change Response Messages Add alert ID to response messages for clarification. BCK-7007 --- alerts_backend/python/app.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index 7d5cb36..c43c7c8 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -167,13 +167,15 @@ def delete_alert(): # return to front end the error, decode and clean the response try: processed_json = result.json() - r_description = f"Error code {result.status_code} with the following description: {processed_json['detail']}" + r_description = f"Error code {result.status_code} with the following description for alert configuration {fa_alert_id}: {processed_json['detail']}" except json.decoder.JSONDecodeError: - r_description = f"Error code {result.status_code} could not be parsed into JSON. The following is the HTML response given: {result.text}" + r_description = f"Error code {result.status_code} for the alert configuration {fa_alert_id} could not be parsed into JSON. The following is the HTML response given: {result.text}" else: # Check if data was inserted into database properly if delete_from_table(fa_alert_id) == -1: - r_description = "Error deleting the alert configuration from the SQL Database" + r_description = "Error deleting the alert configuration from the SQL Database - since it was deleted \ + on AeroAPI but not SQL, this means the alert will still be shown on the table - in order to properly \ + delete the alert please look in your SQL database." else: r_success = True r_description = f"Request sent successfully, alert configuration {fa_alert_id} has been deleted" From 67940139d2bc1073f9d1d1e54f5c1af5d67f4036 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 21 Jul 2022 21:15:38 +0000 Subject: [PATCH 07/10] Sync Alerts with Other Ways of Creating Alerts Modify endpoint of getting alert configurations to also get the alert configurations that were created in AeroAPI besides the alert creation demo and thus sync them up in the frontend. BCK-7184 --- alerts_backend/python/app.py | 54 ++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index c43c7c8..eb725e0 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -1,7 +1,7 @@ """Query alert information from AeroAPI and present it to a frontend service""" import os from datetime import datetime -from typing import Dict, Any, Tuple +from typing import Dict, Any, Tuple, Set import json import requests @@ -141,6 +141,48 @@ def delete_from_table(fa_alert_id: int): return 0 +def get_alerts_not_from_app(existing_alert_ids: Set[int]): + """ + Function to get all alert configurations that were not configured + inside the webapp. Follows exact same format as SQL table, with extra + "is_from_app" column set to False. Takes in existing_alerts parameter + as a list to compare with configured alerts to ensure no overlap. + Returns a dictionary of all the alerts. If no alerts exist, return None. + """ + api_resource = "/alerts" + logger.info(f"Making AeroAPI request to GET {api_resource}") + result = AEROAPI.get(f"{AEROAPI_BASE_URL}{api_resource}") + if not result: + return None + all_alerts = result.json()["alerts"] + if not all_alerts: + return None + alerts_not_from_app = [] + for alert in all_alerts: + if int(alert["id"]) not in existing_alert_ids: + # Don't have to catch key doesn't exist as AeroAPI guarantees + # Keys will exist (just might be null) + holder = { + "fa_alert_id": alert["id"], + "ident": alert["ident"], + "origin": alert["origin"], + "destination": alert["destination"], + "aircraft_type": alert["aircraft_type"], + "start_date": alert["start"], + "end_date": alert["end"], + "max_weekly": 1000, + "eta": alert["eta"], + "arrival": alert["events"]["arrival"], + "cancelled": alert["events"]["cancelled"], + "departure": alert["events"]["departure"], + "diverted": alert["events"]["diverted"], + "filed": alert["events"]["filed"], + "is_from_app": False + } + alerts_not_from_app.append(holder) + return alerts_not_from_app + + @app.route("/delete", methods=["POST"]) def delete_alert(): """ @@ -207,12 +249,20 @@ def get_alert_configs(): via the SQL table. """ data: Dict[str, Any] = {"alert_configurations": []} + existing_alert_ids = set() with engine.connect() as conn: stmt = select(aeroapi_alert_configurations) result = conn.execute(stmt) conn.commit() for row in result: - data["alert_configurations"].append(dict(row)) + row_holder = dict(row) + row_holder["is_from_app"] = True + data["alert_configurations"].append(row_holder) + existing_alert_ids.add(row_holder["fa_alert_id"]) + + # Append alerts not created from app + alerts_not_from_app = get_alerts_not_from_app(existing_alert_ids) + data["alert_configurations"].extend(alerts_not_from_app) return jsonify(data) From 06d71f8631edb83c59baa365a18095fd2d6244f1 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Mon, 25 Jul 2022 20:20:41 +0000 Subject: [PATCH 08/10] Add Endpoint to Edit Alerts Add function for endpoint that allows frontend to send date to update the respective alert configuration, and also add an update function to update the SQLite table. BCL-7009 --- alerts_backend/python/app.py | 153 +++++++++++++++++++++++++++-------- 1 file changed, 118 insertions(+), 35 deletions(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index 0e4a379..5527a79 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -3,6 +3,7 @@ from datetime import datetime from typing import Dict, Any, Tuple, Set +import copy import json import requests from flask import Flask, jsonify, Response, request @@ -11,7 +12,7 @@ from sqlalchemy import (exc, create_engine, MetaData, Table, Column, Integer, Boolean, Text, insert, - Date, DateTime, delete) + Date, DateTime, delete, update) from sqlalchemy.sql import func from sqlalchemy import ( exc, @@ -50,41 +51,42 @@ metadata_obj = MetaData() # Table for alert configurations aeroapi_alert_configurations = Table( - "aeroapi_alert_configurations", - metadata_obj, - Column("fa_alert_id", Integer, primary_key=True), - Column("ident", Text), - Column("origin", Text), - Column("destination", Text), - Column("aircraft_type", Text), - Column("start_date", Date), - Column("end_date", Date), - Column("max_weekly", Integer), - Column("eta", Integer), - Column("arrival", Boolean), - Column("cancelled", Boolean), - Column("departure", Boolean), - Column("diverted", Boolean), - Column("filed", Boolean), - ) + "aeroapi_alert_configurations", + metadata_obj, + Column("fa_alert_id", Integer, primary_key=True), + Column("ident", Text), + Column("origin", Text), + Column("destination", Text), + Column("aircraft_type", Text), + Column("start_date", Date), + Column("end_date", Date), + Column("max_weekly", Integer), + Column("eta", Integer), + Column("arrival", Boolean), + Column("cancelled", Boolean), + Column("departure", Boolean), + Column("diverted", Boolean), + Column("filed", Boolean), +) # Table for POSTed alerts aeroapi_alerts = Table( - "aeroapi_alerts", - metadata_obj, - Column("id", Integer, primary_key=True, autoincrement=True), - Column("time_alert_received", DateTime(timezone=True), server_default=func.now()), # Store time in UTC that the alert was received - Column("long_description", Text), - Column("short_description", Text), - Column("summary", Text), - Column("event_code", Text), - Column("alert_id", Integer), - Column("fa_flight_id", Text), - Column("ident", Text), - Column("registration", Text), - Column("aircraft_type", Text), - Column("origin", Text), - Column("destination", Text) - ) + "aeroapi_alerts", + metadata_obj, + Column("id", Integer, primary_key=True, autoincrement=True), + Column("time_alert_received", DateTime(timezone=True), server_default=func.now()), + # Store time in UTC that the alert was received + Column("long_description", Text), + Column("short_description", Text), + Column("summary", Text), + Column("event_code", Text), + Column("alert_id", Integer), + Column("fa_flight_id", Text), + Column("ident", Text), + Column("registration", Text), + Column("aircraft_type", Text), + Column("origin", Text), + Column("destination", Text) +) def create_tables(): @@ -141,6 +143,24 @@ def delete_from_table(fa_alert_id: int): return 0 +def modify_from_table(fa_alert_id: int, modified_data: Dict[str, Any]): + """ + Updates alert config from SQL Alert Configurations table based on FA Alert ID. + Returns 0 on success, -1 otherwise. + """ + try: + with engine.connect() as conn: + stmt = (update(aeroapi_alert_configurations). + where(aeroapi_alert_configurations.c.fa_alert_id == fa_alert_id)) + conn.execute(stmt, modified_data) + conn.commit() + logger.info(f"Data successfully updated in table {aeroapi_alert_configurations.name}") + except exc.SQLAlchemyError as e: + logger.error(f"SQL error occurred during updating in table {aeroapi_alert_configurations.name}: {e}") + return -1 + return 0 + + def get_alerts_not_from_app(existing_alert_ids: Set[int]): """ Function to get all alert configurations that were not configured @@ -183,6 +203,68 @@ def get_alerts_not_from_app(existing_alert_ids: Set[int]): return alerts_not_from_app +@app.route("/modify", methods=["POST"]) +def modify_alert(): + """ + Function to modify the alert given (with key "fa_alert_id" in the payload). + Modifies the given alert via AeroAPI PUT call and also modifies the respective + alert in the SQLite database. Returns JSON Response in form {"Success": True/False, + "Description": } + """ + r_success: bool = False + r_description: str + # Process json + content_type = request.headers.get("Content-Type") + data: Dict[str, Any] + + if content_type != "application/json": + r_description = "Invalid content sent" + else: + data = request.json + + fa_alert_id = data.pop('fa_alert_id') + + # Make deep copy to send to AeroAPI - needs events in nested dictionary + aeroapi_adjusted_data = copy.deepcopy(data) + aeroapi_adjusted_data["events"] = { + "arrival": aeroapi_adjusted_data.pop('arrival'), + "departure": aeroapi_adjusted_data.pop('departure'), + "cancelled": aeroapi_adjusted_data.pop('cancelled'), + "diverted": aeroapi_adjusted_data.pop('diverted'), + "filed": aeroapi_adjusted_data.pop('filed'), + } + + api_resource = f"/alerts/{fa_alert_id}" + logger.info(f"Making AeroAPI request to PUT {api_resource}") + result = AEROAPI.put(f"{AEROAPI_BASE_URL}{api_resource}", json=aeroapi_adjusted_data) + if result.status_code != 204: + # return to front end the error, decode and clean the response + try: + processed_json = result.json() + r_description = f"Error code {result.status_code} with the following description for alert configuration {fa_alert_id}: {processed_json['detail']}" + except json.decoder.JSONDecodeError: + r_description = f"Error code {result.status_code} for the alert configuration {fa_alert_id} could not be parsed into JSON. The following is the HTML response given: {result.text}" + else: + # Parse into datetime to update in SQLite table + if data["start_date"]: + data["start_date"] = datetime.strptime(data["start_date"], "%Y-%m-%d") + if data["end_date"]: + data["end_date"] = datetime.strptime(data["end_date"], "%Y-%m-%d") + + # Check if data was inserted into database properly + if modify_from_table(fa_alert_id, data) == -1: + r_description = ( + "Error modifying the alert configuration from the SQL Database - since it was modified " + "on AeroAPI but not SQL, this means the alert will still be the original alert on the table - in " + "order to properly modify the alert please look in your SQL database." + ) + else: + r_success = True + r_description = f"Request sent successfully, alert configuration {fa_alert_id} has been updated" + + return jsonify({"Success": r_success, "Description": r_description}) + + @app.route("/delete", methods=["POST"]) def delete_alert(): """ @@ -307,7 +389,8 @@ def handle_alert() -> Tuple[Response, int]: r_status = 200 except KeyError as e: # If value doesn't exist, do not insert into table and produce error - logger.error(f"Alert POST request did not have one or more keys with data. Will process but will return 400: {e}") + logger.error( + f"Alert POST request did not have one or more keys with data. Will process but will return 400: {e}") r_title = "Missing info in request" r_detail = "At least one value to insert in the database is missing in the post request" r_status = 400 From 07efed1d069b120625b4ae2b08af51f65ec8ce7e Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Mon, 25 Jul 2022 21:25:20 +0000 Subject: [PATCH 09/10] Rename Start and End Quick renaming of fields from frontend to send to AeroAPI BCK-7009 --- alerts_backend/python/app.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index 5527a79..dd39646 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -233,6 +233,9 @@ def modify_alert(): "diverted": aeroapi_adjusted_data.pop('diverted'), "filed": aeroapi_adjusted_data.pop('filed'), } + # Rename start and end again + aeroapi_adjusted_data["start"] = aeroapi_adjusted_data.pop("start_date") + aeroapi_adjusted_data["end"] = aeroapi_adjusted_data.pop("end_date") api_resource = f"/alerts/{fa_alert_id}" logger.info(f"Making AeroAPI request to PUT {api_resource}") From de39776d02549cb74296d7f914144b7b8f9f4c8d Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Tue, 2 Aug 2022 16:45:46 +0000 Subject: [PATCH 10/10] Formatting Changes Use lint and format to make small formatting changes. BCK-7009 --- alerts_backend/python/app.py | 52 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/alerts_backend/python/app.py b/alerts_backend/python/app.py index dd39646..24cc843 100644 --- a/alerts_backend/python/app.py +++ b/alerts_backend/python/app.py @@ -10,9 +10,6 @@ from flask.logging import create_logger from flask_cors import CORS -from sqlalchemy import (exc, create_engine, MetaData, Table, - Column, Integer, Boolean, Text, insert, - Date, DateTime, delete, update) from sqlalchemy.sql import func from sqlalchemy import ( exc, @@ -26,6 +23,9 @@ insert, Date, select, + DateTime, + delete, + update, ) AEROAPI_BASE_URL = "https://aeroapi.flightaware.com/aeroapi" @@ -85,7 +85,7 @@ Column("registration", Text), Column("aircraft_type", Text), Column("origin", Text), - Column("destination", Text) + Column("destination", Text), ) @@ -133,12 +133,16 @@ def delete_from_table(fa_alert_id: int): """ try: with engine.connect() as conn: - stmt = delete(aeroapi_alert_configurations).where(aeroapi_alert_configurations.c.fa_alert_id == fa_alert_id) + stmt = delete(aeroapi_alert_configurations).where( + aeroapi_alert_configurations.c.fa_alert_id == fa_alert_id + ) conn.execute(stmt) conn.commit() logger.info(f"Data successfully deleted from {aeroapi_alert_configurations.name}") except exc.SQLAlchemyError as e: - logger.error(f"SQL error occurred during deletion from table {aeroapi_alert_configurations.name}: {e}") + logger.error( + f"SQL error occurred during deletion from table {aeroapi_alert_configurations.name}: {e}" + ) return -1 return 0 @@ -150,13 +154,16 @@ def modify_from_table(fa_alert_id: int, modified_data: Dict[str, Any]): """ try: with engine.connect() as conn: - stmt = (update(aeroapi_alert_configurations). - where(aeroapi_alert_configurations.c.fa_alert_id == fa_alert_id)) + stmt = update(aeroapi_alert_configurations).where( + aeroapi_alert_configurations.c.fa_alert_id == fa_alert_id + ) conn.execute(stmt, modified_data) conn.commit() logger.info(f"Data successfully updated in table {aeroapi_alert_configurations.name}") except exc.SQLAlchemyError as e: - logger.error(f"SQL error occurred during updating in table {aeroapi_alert_configurations.name}: {e}") + logger.error( + f"SQL error occurred during updating in table {aeroapi_alert_configurations.name}: {e}" + ) return -1 return 0 @@ -197,7 +204,7 @@ def get_alerts_not_from_app(existing_alert_ids: Set[int]): "departure": alert["events"]["departure"], "diverted": alert["events"]["diverted"], "filed": alert["events"]["filed"], - "is_from_app": False + "is_from_app": False, } alerts_not_from_app.append(holder) return alerts_not_from_app @@ -222,16 +229,16 @@ def modify_alert(): else: data = request.json - fa_alert_id = data.pop('fa_alert_id') + fa_alert_id = data.pop("fa_alert_id") # Make deep copy to send to AeroAPI - needs events in nested dictionary aeroapi_adjusted_data = copy.deepcopy(data) aeroapi_adjusted_data["events"] = { - "arrival": aeroapi_adjusted_data.pop('arrival'), - "departure": aeroapi_adjusted_data.pop('departure'), - "cancelled": aeroapi_adjusted_data.pop('cancelled'), - "diverted": aeroapi_adjusted_data.pop('diverted'), - "filed": aeroapi_adjusted_data.pop('filed'), + "arrival": aeroapi_adjusted_data.pop("arrival"), + "departure": aeroapi_adjusted_data.pop("departure"), + "cancelled": aeroapi_adjusted_data.pop("cancelled"), + "diverted": aeroapi_adjusted_data.pop("diverted"), + "filed": aeroapi_adjusted_data.pop("filed"), } # Rename start and end again aeroapi_adjusted_data["start"] = aeroapi_adjusted_data.pop("start_date") @@ -263,7 +270,9 @@ def modify_alert(): ) else: r_success = True - r_description = f"Request sent successfully, alert configuration {fa_alert_id} has been updated" + r_description = ( + f"Request sent successfully, alert configuration {fa_alert_id} has been updated" + ) return jsonify({"Success": r_success, "Description": r_description}) @@ -286,7 +295,7 @@ def delete_alert(): r_description = "Invalid content sent" else: data = request.json - fa_alert_id = data['fa_alert_id'] + fa_alert_id = data["fa_alert_id"] api_resource = f"/alerts/{fa_alert_id}" logger.info(f"Making AeroAPI request to DELETE {api_resource}") result = AEROAPI.delete(f"{AEROAPI_BASE_URL}{api_resource}", json=data) @@ -305,7 +314,9 @@ def delete_alert(): delete the alert please look in your SQL database." else: r_success = True - r_description = f"Request sent successfully, alert configuration {fa_alert_id} has been deleted" + r_description = ( + f"Request sent successfully, alert configuration {fa_alert_id} has been deleted" + ) return jsonify({"Success": r_success, "Description": r_description}) @@ -393,7 +404,8 @@ def handle_alert() -> Tuple[Response, int]: except KeyError as e: # If value doesn't exist, do not insert into table and produce error logger.error( - f"Alert POST request did not have one or more keys with data. Will process but will return 400: {e}") + f"Alert POST request did not have one or more keys with data. Will process but will return 400: {e}" + ) r_title = "Missing info in request" r_detail = "At least one value to insert in the database is missing in the post request" r_status = 400