diff --git a/src/server/BreCal/__init__.py b/src/server/BreCal/__init__.py index c2012e2..c3674bc 100644 --- a/src/server/BreCal/__init__.py +++ b/src/server/BreCal/__init__.py @@ -69,7 +69,7 @@ def create_app(test_config=None, instance_path=None): app.register_blueprint(history.bp) app.register_blueprint(ports.bp) - logging.basicConfig(filename='brecaldevel.log', level=logging.DEBUG, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s') + logging.basicConfig(filename='brecal.log', level=logging.WARNING, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s') local_db.initPool(os.path.dirname(app.instance_path)) logging.info('App started') diff --git a/src/server/BreCal/impl/berths.py b/src/server/BreCal/impl/berths.py index f00a9e8..79672d4 100644 --- a/src/server/BreCal/impl/berths.py +++ b/src/server/BreCal/impl/berths.py @@ -10,6 +10,7 @@ def GetBerths(options): No parameters, gets all entries """ + pooledConnection = None try: pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) diff --git a/src/server/BreCal/impl/history.py b/src/server/BreCal/impl/history.py index 08cb06e..8129c24 100644 --- a/src/server/BreCal/impl/history.py +++ b/src/server/BreCal/impl/history.py @@ -16,6 +16,8 @@ def GetHistory(options): options["shipcall_id"]: **Id of shipcall**. """ + pooledConnection = None + data = [] try: pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -26,10 +28,6 @@ def GetHistory(options): data = commands.query("SELECT id, participant_id, shipcall_id, timestamp, eta, type, operation FROM history WHERE shipcall_id = ?shipcallid?", model=History.from_query_row, param={"shipcallid" : options["shipcall_id"]}) - - - pooledConnection.close() - except Exception as ex: pdb.pm() logging.error(ex) @@ -37,6 +35,9 @@ def GetHistory(options): result = {} result["error_field"] = "call failed" return json.dumps("call failed"), 500 + finally: + if pooledConnection is not None: + pooledConnection.close() return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} diff --git a/src/server/BreCal/impl/login.py b/src/server/BreCal/impl/login.py index 2810b6a..c2a2fa6 100644 --- a/src/server/BreCal/impl/login.py +++ b/src/server/BreCal/impl/login.py @@ -6,14 +6,15 @@ import bcrypt from ..schemas import model from .. import local_db from ..services import jwt_handler -from BreCal.database.sql_queries import SQLQuery def GetUser(options): + pooledConnection = None + try: if "password" in options and "username" in options: - hash = bcrypt.hashpw(options["password"].encode('utf-8'), bcrypt.gensalt( 12 )).decode('utf8') + pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) # query = SQLQuery.get_user() @@ -63,7 +64,3 @@ def GetUser(options): finally: if pooledConnection is not None: pooledConnection.close() - -# $2b$12$uWLE0r32IrtCV30WkMbVwOdltgeibymZyYAf4ZnQb2Bip8hrkGGwG -# $2b$12$.vEapj9xU8z0RK0IpIGeYuRIl0ktdMt4XdJQBhVn.3K2hmvm7qD3y -# $2b$12$yL3PiseU70ciwEuMVM4OtuMwR6tNuIT9vvBiBG/uyMrPxa16E2Zqu \ No newline at end of file diff --git a/src/server/BreCal/impl/notifications.py b/src/server/BreCal/impl/notifications.py index 3a95e0a..ea1ecb5 100644 --- a/src/server/BreCal/impl/notifications.py +++ b/src/server/BreCal/impl/notifications.py @@ -11,13 +11,12 @@ def GetNotifications(token): No parameters, gets all entries """ + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) data = commands.query("SELECT id, shipcall_id, participant_id, level, type, message, created, modified FROM notification " + "WHERE level = 2", model=model.Notification.from_query_row) - pooledConnection.close() except Exception as ex: logging.error(ex) @@ -25,6 +24,9 @@ def GetNotifications(token): result = {} result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} + finally: + if pooledConnection is not None: + pooledConnection.close() return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} diff --git a/src/server/BreCal/impl/participant.py b/src/server/BreCal/impl/participant.py index 421523c..8f512b2 100644 --- a/src/server/BreCal/impl/participant.py +++ b/src/server/BreCal/impl/participant.py @@ -12,6 +12,7 @@ def GetParticipant(options): options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call. """ + pooledConnection = None try: pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) diff --git a/src/server/BreCal/impl/ports.py b/src/server/BreCal/impl/ports.py index 0a721ec..799119e 100644 --- a/src/server/BreCal/impl/ports.py +++ b/src/server/BreCal/impl/ports.py @@ -11,6 +11,7 @@ def GetPorts(token): No parameters, gets all entries """ + pooledConnection = None try: pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) diff --git a/src/server/BreCal/impl/shipcalls.py b/src/server/BreCal/impl/shipcalls.py index e6f0779..fbb7eef 100644 --- a/src/server/BreCal/impl/shipcalls.py +++ b/src/server/BreCal/impl/shipcalls.py @@ -18,8 +18,8 @@ def GetShipcalls(options): No parameters, gets all entries """ + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) # query = SQLQuery.get_shipcalls(options) @@ -70,8 +70,8 @@ def PostShipcalls(schemaModel): """ # This creates a *new* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -192,8 +192,8 @@ def PutShipcalls(schemaModel): """ # This updates an *existing* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -205,7 +205,6 @@ def PutShipcalls(schemaModel): theshipcall = commands.query_single_or_default("SELECT * FROM shipcall where id = ?id?", sentinel, param={"id" : schemaModel["id"]}) if theshipcall is sentinel: - pooledConnection.close() return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'} was_canceled = theshipcall["canceled"] diff --git a/src/server/BreCal/impl/ships.py b/src/server/BreCal/impl/ships.py index 93a5d4d..726a725 100644 --- a/src/server/BreCal/impl/ships.py +++ b/src/server/BreCal/impl/ships.py @@ -11,8 +11,8 @@ def GetShips(token): No parameters, gets all entries """ + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) # query = SQLQuery.get_ships() @@ -44,8 +44,8 @@ def PostShip(schemaModel): # TODO: Validate the incoming data # This creates a *new* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -83,8 +83,6 @@ def PostShip(schemaModel): # new_id = commands.execute_scalar(nquery) new_id = commands.execute_scalar("select last_insert_id()") - pooledConnection.close() - return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: @@ -93,6 +91,9 @@ def PostShip(schemaModel): result = {} result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} + finally: + if pooledConnection is not None: + pooledConnection.close() def PutShip(schemaModel): @@ -101,8 +102,8 @@ def PutShip(schemaModel): """ # This updates an *existing* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -125,8 +126,6 @@ def PutShip(schemaModel): affected_rows = commands.execute(query, param=schemaModel) - pooledConnection.close() - return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: @@ -135,6 +134,9 @@ def PutShip(schemaModel): result = {} result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} + finally: + if pooledConnection is not None: + pooledConnection.close() def DeleteShip(options): @@ -143,16 +145,14 @@ def DeleteShip(options): options["id"] """ + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) # query = SQLQuery.get_ship_delete_by_id() # affected_rows = commands.execute(query, param={"id" : options["id"]}) affected_rows = commands.execute("UPDATE ship SET deleted = 1 WHERE id = ?id?", param={"id" : options["id"]}) - pooledConnection.close() - if affected_rows == 1: return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} @@ -165,4 +165,7 @@ def DeleteShip(options): print(ex) result = {} result["error_field"] = "call failed" - return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} \ No newline at end of file + return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} + finally: + if pooledConnection is not None: + pooledConnection.close() diff --git a/src/server/BreCal/impl/times.py b/src/server/BreCal/impl/times.py index e12f624..c7f99bc 100644 --- a/src/server/BreCal/impl/times.py +++ b/src/server/BreCal/impl/times.py @@ -18,8 +18,8 @@ def GetTimes(options): """ + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) # query = SQLQuery.get_times() @@ -28,7 +28,6 @@ def GetTimes(options): "zone_entry, zone_entry_fixed, operations_start, operations_end, remarks, shipcall_id, participant_id, " + "berth_id, berth_info, pier_side, participant_type, created, modified, ata, atd, eta_interval_end, etd_interval_end FROM times " + "WHERE times.shipcall_id = ?scid?", model=model.Times, param={"scid" : options["shipcall_id"]}) - pooledConnection.close() except Exception as ex: logging.error(traceback.format_exc()) @@ -38,6 +37,10 @@ def GetTimes(options): result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} + finally: + if pooledConnection is not None: + pooledConnection.close() + return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} @@ -51,8 +54,8 @@ def PostTimes(schemaModel): # TODO: Validate the upload data # This creates a *new* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -119,8 +122,8 @@ def PutTimes(schemaModel): """ # This updates an *existing* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -177,8 +180,8 @@ def DeleteTimes(options): options["id"] """ + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) shipcall_id = commands.execute_scalar("SELECT shipcall_id FROM times WHERE id = ?id?", param={"id" : options["id"]}) @@ -207,4 +210,4 @@ def DeleteTimes(options): finally: if pooledConnection is not None: - pooledConnection.close() \ No newline at end of file + pooledConnection.close() diff --git a/src/server/BreCal/impl/user.py b/src/server/BreCal/impl/user.py index 6d7fd45..a3ce1c1 100644 --- a/src/server/BreCal/impl/user.py +++ b/src/server/BreCal/impl/user.py @@ -14,8 +14,8 @@ def PutUser(schemaModel): """ # This updates an *existing* entry + pooledConnection = None try: - pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) @@ -26,7 +26,6 @@ def PutUser(schemaModel): # theuser = commands.query_single_or_default(query, sentinel, param={"id" : schemaModel["id"]}, model=model.User) theuser = commands.query_single_or_default("SELECT * FROM user where id = ?id?", sentinel, param={"id" : schemaModel["id"]}, model=model.User) if theuser is sentinel: - pooledConnection.close() # #TODO: result = {"message":"no such record"} -> json.dumps return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'} diff --git a/src/server/BreCal/local_db.py b/src/server/BreCal/local_db.py index ed154fd..4bb15c5 100644 --- a/src/server/BreCal/local_db.py +++ b/src/server/BreCal/local_db.py @@ -23,7 +23,7 @@ def _build_pool_config(connection_data, pool_name, pool_size): return pool_config -def initPool(instancePath, connection_filename="connection_data_devel.json", +def initPool(instancePath, connection_filename="connection_data_prod.json", pool_name="brecal_pool", pool_size=10): """ Initialize the MySQL connection pool and load email credentials. @@ -33,7 +33,7 @@ def initPool(instancePath, connection_filename="connection_data_devel.json", if config_path is None: config_path = os.path.join(instancePath, f'../../../secure/{connection_filename}') - config_path = 'C:\\temp\\connection_data_test.json' + # config_path = 'C:\\temp\\connection_data_test.json' print(config_path) if not os.path.exists(config_path): @@ -54,10 +54,10 @@ def initPool(instancePath, connection_filename="connection_data_devel.json", finally: conn_from_pool.close() - credentials_file = "email_credentials_devel.json" + credentials_file = "email_credentials_test.json" credentials_path = os.path.join(instancePath, f'../../../secure/{credentials_file}') - credentials_path = 'C:\\temp\\email_credentials_test.json' + # credentials_path = 'C:\\temp\\email_credentials_test.json' if not os.path.exists(credentials_path): print('cannot find ' + os.path.abspath(credentials_path)) diff --git a/src/server/BreCal/services/schedule_routines.py b/src/server/BreCal/services/schedule_routines.py index 9971fe2..2889e50 100644 --- a/src/server/BreCal/services/schedule_routines.py +++ b/src/server/BreCal/services/schedule_routines.py @@ -31,6 +31,7 @@ def UpdateShipcalls(options:dict = {'past_days':2}): options: key: 'past_days'. Is used to execute a filtered query of all available shipcalls. Defaults to 2 (days) """ + pooledConnection = None try: pooledConnection = getPoolConnection() commands = pydapper.using(pooledConnection) @@ -49,10 +50,11 @@ def UpdateShipcalls(options:dict = {'past_days':2}): # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=shipcall_id) # new_id (last insert id) refers to the shipcall id - pooledConnection.close() - except Exception as ex: logging.error(ex) + finally: + if pooledConnection is not None: + pooledConnection.close() return def UpdateNotifications(cooldown_in_mins:int=10): @@ -61,6 +63,7 @@ def UpdateNotifications(cooldown_in_mins:int=10): notification is updated to state 1 and a notification is received by the user """ + pooledConnection = None try: pooledConnection = getPoolConnection() commands = pydapper.using(pooledConnection) @@ -70,32 +73,39 @@ def UpdateNotifications(cooldown_in_mins:int=10): for notification in data: commands.execute("UPDATE notification SET level = 1 WHERE id = ?id?", param={"id":notification.id}) - pooledConnection.close() except Exception as ex: logging.error(ex) + finally: + if pooledConnection is not None: + pooledConnection.close() def ClearNotifications(max_age_in_days:int=3): """ This function clears all notifications in state ("level") 2 that are older than x days """ + pooledConnection = None try: pooledConnection = getPoolConnection() commands = pydapper.using(pooledConnection) query = f"DELETE FROM notification WHERE level = 2 and created < TIMESTAMP(NOW() - INTERVAL {max_age_in_days} DAY)" result = commands.execute(query) - pooledConnection.close() if(result > 0): logging.info(f"Deleted {result} notifications") except Exception as ex: logging.error(ex) + finally: + if pooledConnection is not None: + pooledConnection.close() def SendEmails(email_dict): """ This function sends emails to all users in the emaildict """ + pooledConnection = None + conn = None try: pooledConnection = getPoolConnection() commands = pydapper.using(pooledConnection) @@ -177,10 +187,13 @@ def SendEmails(email_dict): finally: if conn is not None: conn.quit() + if pooledConnection is not None: + pooledConnection.close() def SendNotifications(): # perhaps this will be moved somewhere else later + pooledConnection = None try: # find all notifications in level 1 pooledConnection = getPoolConnection() @@ -271,6 +284,7 @@ def add_function_to_schedule_send_notifications(interval_in_minutes:int=1): return def eval_next_24_hrs(): + pooledConnection = None try: pooledConnection = getPoolConnection() commands = pydapper.using(pooledConnection) diff --git a/src/server/BreCal/validators/validation_rules.py b/src/server/BreCal/validators/validation_rules.py index 3cc5729..3ceea99 100644 --- a/src/server/BreCal/validators/validation_rules.py +++ b/src/server/BreCal/validators/validation_rules.py @@ -90,40 +90,43 @@ class ValidationRules(ValidationRuleFunctions): if evaluation_states_old is not None and evaluation_states_new is not None: if len(evaluation_states_old) == 1 and len(evaluation_states_new) == 1: if evaluation_states_old[0] != evaluation_states_new[0]: - pooledConnection = getPoolConnection() - commands = pydapper.using(pooledConnection) - notification_type = 3 # RED (mapped to time_conflict) - if evaluation_states_new[0] == 2: - match evaluation_states_old[0]: - case 0: - send_notification = True - case 1: - send_notification = True - notification_type = 6 # YELLOW (mapped to missing_data) - if evaluation_states_new[0] == 3: - match evaluation_states_old[0]: - case 0: - send_notification = True - case 1: - send_notification = True - case 2: - send_notification = True + pooledConnection = None + try: + pooledConnection = getPoolConnection() + commands = pydapper.using(pooledConnection) + notification_type = 3 # RED (mapped to time_conflict) + if evaluation_states_new[0] == 2: + match evaluation_states_old[0]: + case 0: + send_notification = True + case 1: + send_notification = True + notification_type = 6 # YELLOW (mapped to missing_data) + if evaluation_states_new[0] == 3: + match evaluation_states_old[0]: + case 0: + send_notification = True + case 1: + send_notification = True + case 2: + send_notification = True - if send_notification: - query = f"INSERT INTO notification (shipcall_id, type, level, message) VALUES (?shipcall_id?, {notification_type}, 0, ?message?)" - commands.execute(query, param={"shipcall_id" : int(shipcall_df.index[0]), "message" : violations[0]}) + if send_notification: + query = f"INSERT INTO notification (shipcall_id, type, level, message) VALUES (?shipcall_id?, {notification_type}, 0, ?message?)" + commands.execute(query, param={"shipcall_id" : int(shipcall_df.index[0]), "message" : violations[0]}) - if evaluation_states_new[0] == 1 and evaluation_states_old[0] != 0: # this resolves the conflict - query = f"SELECT * from notification where shipcall_id = ?shipcall_id? and type = {notification_type} and level = 0" - existing_notification = commands.query(query, param={"shipcall_id" : int(shipcall_df.index[0])}) - if len(existing_notification) > 0: - query = "DELETE from notification where id = ?id?" - commands.execute(query, param={"id" : existing_notification[0]["id"]}) - else: - query = "INSERT INTO notification (shipcall_id, type, level) VALUES (?shipcall_id?, 4, 0)" - commands.execute(query, param={"shipcall_id" : int(shipcall_df.index[0])}) - - pooledConnection.close() + if evaluation_states_new[0] == 1 and evaluation_states_old[0] != 0: # this resolves the conflict + query = f"SELECT * from notification where shipcall_id = ?shipcall_id? and type = {notification_type} and level = 0" + existing_notification = commands.query(query, param={"shipcall_id" : int(shipcall_df.index[0])}) + if len(existing_notification) > 0: + query = "DELETE from notification where id = ?id?" + commands.execute(query, param={"id" : existing_notification[0]["id"]}) + else: + query = "INSERT INTO notification (shipcall_id, type, level) VALUES (?shipcall_id?, 4, 0)" + commands.execute(query, param={"shipcall_id" : int(shipcall_df.index[0])}) + finally: + if pooledConnection is not None: + pooledConnection.close() # build the list of 'evaluation_notifications_sent'. The value is 'False', when a notification should be created diff --git a/src/server/flaskapp.wsgi b/src/server/flaskapp.wsgi index 17846d8..a043504 100644 --- a/src/server/flaskapp.wsgi +++ b/src/server/flaskapp.wsgi @@ -2,7 +2,7 @@ import os import sys import logging -sys.path.insert(0, '/var/www/brecal_devel/src/server') +sys.path.insert(0, '/var/www/brecal/src/server') sys.path.insert(0, '/var/www/venv/lib/python3.12/site-packages/') import schedule