diff --git a/src/server/BreCal/api/__init__.py b/src/server/BreCal/api/__init__.py index 1803976..a8b173a 100644 --- a/src/server/BreCal/api/__init__.py +++ b/src/server/BreCal/api/__init__.py @@ -2,7 +2,8 @@ import typing import datetime # global dictionary, which informs about the latest change of a given database (e.g., 'berths') -latest_get_request_dict = {database:None for database in ["berths", "history", "notifications", "participant", "shipcalls", "ships", "times", "user"]} +# initialize all values as null (None) +latest_get_request_dict = {database:None for database in ["berths", "history", "notifications", "participants", "shipcalls", "ships", "times"]} def update_latest_modification_time(key:str, modification_time:datetime.datetime)->None: """ @@ -10,7 +11,7 @@ def update_latest_modification_time(key:str, modification_time:datetime.datetime *if* the time is more recent than the currently stored value """ global latest_get_request_dict - print(f"(update_latest_modification_time INFO): before executing the funtion", latest_get_request_dict, key, modification_time) + value = latest_get_request_dict.get(key,None) if value is None: # when there is no value stored for the key, update the value @@ -19,7 +20,7 @@ def update_latest_modification_time(key:str, modification_time:datetime.datetime # when the modification date is more recent than the stored value, update it if modification_time > value: latest_get_request_dict[key] = modification_time - print(f"(update_latest_modification_time INFO): after executing the funtion", latest_get_request_dict, key, modification_time) + return def get_latest_modification_time(key:str)->typing.Optional[str]: @@ -27,8 +28,10 @@ def get_latest_modification_time(key:str)->typing.Optional[str]: This function returns the latest modification time in .isoformat, if a datetime is stored for the respective key in {latest_get_request_dict}. When there has not yet been an update, this function returns None """ + global latest_get_request_dict + value = latest_get_request_dict.get(key,None) if isinstance(value,datetime.datetime): return value.isoformat() return value # None - \ No newline at end of file + diff --git a/src/server/BreCal/api/history.py b/src/server/BreCal/api/history.py index c1fe5ad..4d087a0 100644 --- a/src/server/BreCal/api/history.py +++ b/src/server/BreCal/api/history.py @@ -7,7 +7,7 @@ bp = Blueprint('history', __name__) @bp.route('/history', methods=['get']) @auth_guard() # no restriction by role -def GetParticipant(): +def GetParticipant(): # #TODO: rename? Naming might be a copy-paste typo if 'Authorization' in request.headers: token = request.headers.get('Authorization') @@ -19,3 +19,13 @@ def GetParticipant(): else: return json.dumps("not authenticated"), 403 + +@bp.route('/getlatesthistory', methods=['get']) +@auth_guard() # no restriction by role +def GetLatestHistory(): + + if 'Authorization' in request.headers: + token = request.headers.get('Authorization') + return impl.history.GetLatestHistory(token) + else: + return json.dumps("not authenticated"), 403 diff --git a/src/server/BreCal/api/notifications.py b/src/server/BreCal/api/notifications.py index 48a2a44..5a7e434 100644 --- a/src/server/BreCal/api/notifications.py +++ b/src/server/BreCal/api/notifications.py @@ -16,4 +16,15 @@ def GetNotifications(): return impl.notifications.GetNotifications(options) else: logging.warning("attempt to load notifications without shipcall id") - return json.dumps("missing argument"), 400 \ No newline at end of file + return json.dumps("missing argument"), 400 + +@bp.route('/getlatestnotifications', methods=['get']) +@auth_guard() # no restriction by role +def GetLatestNotifications(): + + if 'Authorization' in request.headers: + token = request.headers.get('Authorization') + return impl.notifications.GetLatestNotifications(token) + else: + return json.dumps("not authenticated"), 403 + diff --git a/src/server/BreCal/api/participant.py b/src/server/BreCal/api/participant.py index 65887f9..60d7743 100644 --- a/src/server/BreCal/api/participant.py +++ b/src/server/BreCal/api/participant.py @@ -17,3 +17,12 @@ def GetParticipant(): else: return json.dumps("not authenticated"), 403 +@bp.route('/getlatestparticipants', methods=['get']) +@auth_guard() # no restriction by role +def GetLatestParticipants(): + + if 'Authorization' in request.headers: + token = request.headers.get('Authorization') + return impl.participant.GetLatestParticipants(token) + else: + return json.dumps("not authenticated"), 403 diff --git a/src/server/BreCal/api/shipcalls.py b/src/server/BreCal/api/shipcalls.py index 396dc93..1b22dff 100644 --- a/src/server/BreCal/api/shipcalls.py +++ b/src/server/BreCal/api/shipcalls.py @@ -53,3 +53,12 @@ def PutShipcalls(): return json.dumps("bad format"), 400 return impl.shipcalls.PutShipcalls(loadedModel) + +@bp.route('/getlatestshipcalls', methods=['get']) +@auth_guard() # no restriction by role +def GetLatestShipcalls(): + if 'Authorization' in request.headers: + token = request.headers.get('Authorization') + return impl.shipcalls.GetLatestShipcalls(token) + else: + return json.dumps("not authenticated"), 403 diff --git a/src/server/BreCal/api/ships.py b/src/server/BreCal/api/ships.py index e31147e..6720a4a 100644 --- a/src/server/BreCal/api/ships.py +++ b/src/server/BreCal/api/ships.py @@ -66,3 +66,13 @@ def DeleteShip(): return json.dumps("bad format"), 400 return impl.ships.DeleteShip(options) + +@bp.route('/getlatestships', methods=['get']) +@auth_guard() # no restriction by role +def GetLatestShips(): + if 'Authorization' in request.headers: + token = request.headers.get('Authorization') + return impl.ships.GetLatestShips(token) + else: + return json.dumps("not authenticated"), 403 + diff --git a/src/server/BreCal/api/times.py b/src/server/BreCal/api/times.py index 2c90397..9e8f30d 100644 --- a/src/server/BreCal/api/times.py +++ b/src/server/BreCal/api/times.py @@ -67,3 +67,13 @@ def DeleteTimes(): else: logging.warning("Times delete missing id argument") return json.dumps("missing argument"), 400 + +@bp.route('/getlatesttimes', methods=['get']) +@auth_guard() # no restriction by role +def GetLatestTimes(): + + if 'Authorization' in request.headers: + token = request.headers.get('Authorization') + return impl.times.GetLatestTimes(token) + else: + return json.dumps("not authenticated"), 403 diff --git a/src/server/BreCal/impl/berths.py b/src/server/BreCal/impl/berths.py index cc6baf3..d3ab61b 100644 --- a/src/server/BreCal/impl/berths.py +++ b/src/server/BreCal/impl/berths.py @@ -34,7 +34,8 @@ def GetBerths(token): def GetLatestBerths(token): """ - Returns a datetime of the latest modification within the berths database. When there has not yet been a modification, this method returns null. + Returns a datetime of the latest modification within the 'berth' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} # #TODO: should this become a data model? """ diff --git a/src/server/BreCal/impl/history.py b/src/server/BreCal/impl/history.py index 2fa7e1c..f6b99df 100644 --- a/src/server/BreCal/impl/history.py +++ b/src/server/BreCal/impl/history.py @@ -7,7 +7,7 @@ from ..schemas import model from ..schemas.model import History from .. import local_db -from BreCal.api import latest_get_request_dict, update_latest_modification_time +from BreCal.api import latest_get_request_dict, update_latest_modification_time, get_latest_modification_time def GetHistory(options): @@ -38,3 +38,25 @@ def GetHistory(options): return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} + +def GetLatestHistory(token): + """ + Returns a datetime of the latest modification within the 'history' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} + + # #TODO: should this become a data model? + """ + + try: + modification_time = get_latest_modification_time(key="history") + data = {"key":"history", "value":modification_time} + + return json.dumps(data), 200, {'Content-Type': 'application/json; charset=utf-8'} + + except Exception as ex: + logging.error(ex) + print(ex) + result = {} + result["message"] = "call failed" + return json.dumps(result), 500 + diff --git a/src/server/BreCal/impl/notifications.py b/src/server/BreCal/impl/notifications.py index 793f4c7..9ca02ca 100644 --- a/src/server/BreCal/impl/notifications.py +++ b/src/server/BreCal/impl/notifications.py @@ -4,7 +4,7 @@ import pydapper from ..schemas import model from .. import local_db -from BreCal.api import latest_get_request_dict, update_latest_modification_time +from BreCal.api import latest_get_request_dict, update_latest_modification_time, get_latest_modification_time def GetNotifications(options): """ @@ -31,3 +31,25 @@ def GetNotifications(options): return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} +def GetLatestNotifications(token): + """ + Returns a datetime of the latest modification within the 'notification' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} + + # #TODO: should this become a data model? + """ + + try: + modification_time = get_latest_modification_time(key="notifications") + data = {"key":"notifications", "value":modification_time} + + return json.dumps(data), 200, {'Content-Type': 'application/json; charset=utf-8'} + + except Exception as ex: + logging.error(ex) + print(ex) + result = {} + result["message"] = "call failed" + return json.dumps(result), 500 + + diff --git a/src/server/BreCal/impl/participant.py b/src/server/BreCal/impl/participant.py index 174a3f5..2f334a9 100644 --- a/src/server/BreCal/impl/participant.py +++ b/src/server/BreCal/impl/participant.py @@ -4,7 +4,7 @@ import pydapper from ..schemas import model from .. import local_db -from BreCal.api import latest_get_request_dict, update_latest_modification_time +from BreCal.api import latest_get_request_dict, update_latest_modification_time, get_latest_modification_time def GetParticipant(options): """ @@ -34,3 +34,25 @@ def GetParticipant(options): if pooledConnection is not None: pooledConnection.close() + + +def GetLatestParticipants(token): + """ + Returns a datetime of the latest modification within the 'participant' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} + + # #TODO: should this become a data model? + """ + + try: + modification_time = get_latest_modification_time(key="participants") + data = {"key":"participants", "value":modification_time} + + return json.dumps(data), 200, {'Content-Type': 'application/json; charset=utf-8'} + + except Exception as ex: + logging.error(ex) + print(ex) + result = {} + result["message"] = "call failed" + return json.dumps(result), 500 diff --git a/src/server/BreCal/impl/shipcalls.py b/src/server/BreCal/impl/shipcalls.py index c02c7c4..1577605 100644 --- a/src/server/BreCal/impl/shipcalls.py +++ b/src/server/BreCal/impl/shipcalls.py @@ -2,13 +2,14 @@ import json import logging import traceback import pydapper +import datetime from ..schemas import model from .. import local_db from ..services.auth_guard import check_jwt from BreCal.database.update_database import evaluate_shipcall_state -from BreCal.api import latest_get_request_dict, update_latest_modification_time +from BreCal.api import latest_get_request_dict, update_latest_modification_time, get_latest_modification_time def GetShipcalls(options): """ @@ -141,6 +142,9 @@ def PostShipcalls(schemaModel): user_data = check_jwt() query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 1)" commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]}) + + # track the latest update in the global dictionary + update_latest_modification_time(key="shipcalls",modification_time=datetime.datetime.now()) # new_id return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'} @@ -244,6 +248,9 @@ def PutShipcalls(schemaModel): query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 2)" commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]}) + # track the latest update in the global dictionary + update_latest_modification_time(key="shipcalls",modification_time=datetime.datetime.now()) # schemaModel["id"] + return json.dumps({"id" : schemaModel["id"]}), 200 except Exception as ex: @@ -258,3 +265,24 @@ def PutShipcalls(schemaModel): if pooledConnection is not None: pooledConnection.close() + +def GetLatestShipcalls(token): + """ + Returns a datetime of the latest modification within the 'shipcall' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} + + # #TODO: should this become a data model? + """ + + try: + modification_time = get_latest_modification_time(key="shipcalls") + data = {"key":"shipcalls", "value":modification_time} + + return json.dumps(data), 200, {'Content-Type': 'application/json; charset=utf-8'} + + except Exception as ex: + logging.error(ex) + print(ex) + result = {} + result["message"] = "call failed" + return json.dumps(result), 500 diff --git a/src/server/BreCal/impl/ships.py b/src/server/BreCal/impl/ships.py index 69964d8..9b2107c 100644 --- a/src/server/BreCal/impl/ships.py +++ b/src/server/BreCal/impl/ships.py @@ -5,7 +5,7 @@ import datetime from ..schemas import model from .. import local_db -from BreCal.api import latest_get_request_dict, update_latest_modification_time +from BreCal.api import latest_get_request_dict, update_latest_modification_time, get_latest_modification_time def GetShips(token): """ @@ -158,4 +158,25 @@ def DeleteShip(options): print(ex) result = {} result["message"] = "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'} + +def GetLatestShips(token): + """ + Returns a datetime of the latest modification within the 'ship' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} + + # #TODO: should this become a data model? + """ + + try: + modification_time = get_latest_modification_time(key="ships") + data = {"key":"ships", "value":modification_time} + + return json.dumps(data), 200, {'Content-Type': 'application/json; charset=utf-8'} + + except Exception as ex: + logging.error(ex) + print(ex) + result = {} + result["message"] = "call failed" + return json.dumps(result), 500 diff --git a/src/server/BreCal/impl/times.py b/src/server/BreCal/impl/times.py index 966599f..6161313 100644 --- a/src/server/BreCal/impl/times.py +++ b/src/server/BreCal/impl/times.py @@ -2,11 +2,12 @@ import json import logging import traceback import pydapper +import datetime from ..schemas import model from .. import local_db from ..services.auth_guard import check_jwt -from BreCal.api import latest_get_request_dict, update_latest_modification_time +from BreCal.api import latest_get_request_dict, update_latest_modification_time, get_latest_modification_time from BreCal.database.update_database import evaluate_shipcall_state @@ -92,6 +93,9 @@ def PostTimes(schemaModel): user_data = check_jwt() query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 2, 1)" commands.execute(query, {"scid" : schemaModel["shipcall_id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]}) + + # track the latest update in the global dictionary + update_latest_modification_time(key="times", modification_time=datetime.datetime.now()) # new_id return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'} @@ -137,6 +141,7 @@ def PutTimes(schemaModel): query += "WHERE id = ?id?" affected_rows = commands.execute(query, param=schemaModel) + new_id = commands.execute_scalar("select last_insert_id()") # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall' evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id' @@ -152,6 +157,9 @@ def PutTimes(schemaModel): # if affected_rows == 1: # this doesn't work as expected + # track the latest update in the global dictionary + update_latest_modification_time(key="times", modification_time=datetime.datetime.now()) # new_id + return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: @@ -186,6 +194,10 @@ def DeleteTimes(options): query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?shipcall_id?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 2, 3)" commands.execute(query, {"pid" : user_data["participant_id"], "shipcall_id" : shipcall_id, "uid" : user_data["id"]}) + # track the latest update in the global dictionary + ###### could use a query similar to this one: modification_time = commands.execute_scalar("SELECT modified FROM times WHERE id = ?id?", param={"id" : options["id"]}) # clarify: when modified is null, created should be used... + update_latest_modification_time(key="times", modification_time=datetime.datetime.now()) # options["id"] + if affected_rows == 1: return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} @@ -202,4 +214,25 @@ def DeleteTimes(options): finally: if pooledConnection is not None: - pooledConnection.close() \ No newline at end of file + pooledConnection.close() + +def GetLatestTimes(token): + """ + Returns a datetime of the latest modification within the 'times' database. When there has not yet been a modification, this method returns null. + Always creates an output dictionary with the format {key:string, value:str (datetime isoformat)} + + # #TODO: should this become a data model? + """ + + try: + modification_time = get_latest_modification_time(key="times") + data = {"key":"times", "value":modification_time} + + return json.dumps(data), 200, {'Content-Type': 'application/json; charset=utf-8'} + + except Exception as ex: + logging.error(ex) + print(ex) + result = {} + result["message"] = "call failed" + return json.dumps(result), 500