diff --git a/src/server/BreCal/database/sql_utils.py b/src/server/BreCal/database/sql_utils.py index 7c9708d..cd2606d 100644 --- a/src/server/BreCal/database/sql_utils.py +++ b/src/server/BreCal/database/sql_utils.py @@ -1,6 +1,11 @@ -from BreCal.database.sql_handler import execute_sql_query_standalone +import pydapper import datetime +from BreCal import local_db +from BreCal.schemas import model +from BreCal.database.sql_queries import SQLQuery +from BreCal.database.sql_handler import execute_sql_query_standalone + def get_user_data_for_id(user_id:int, expiration_time:int=90): """debugging function, which is useful to pull user_data from the database, which may be used to create stub data and unit tests""" query = "SELECT * FROM user where id = ?id?" @@ -33,4 +38,96 @@ def get_port_ids_for_participant_id(participant_id:int): """helper function to load all port ids for a participant""" query = "SELECT port_id FROM participant_port_map where participant_id = ?participant_id?" pdata = execute_sql_query_standalone(query=query, param={"participant_id":participant_id}) - return pdata \ No newline at end of file + return pdata + +def filter_berths_by_port(berths:list[model.Berth], participant:model.Participant)->list[model.Berth]: + """ + this function filters a list of berths by the participant's assigned ports. + + Uses: + berth.port_id (the port's int id of each berth) + Participant.ports (a list of int ids) + + returns: berths (filtered) + """ + berths = [berth for berth in berths if berth.port_id in participant.ports] + return berths + + +def filter_berths_by_users_assigned_ports(berths:list[model.Berth], user_data:dict, commands=None)->list[model.Berth]: + """ + this function uses the user_id to filter a list of berths. Only those berths, which belong to the Participant's assigned + port list are relevant. + + Uses: + berth.port_id (the port's int id of each berth) + + user_data 'id' to obtain Participant + Participant.ports (a list of int ids) + + returns: berths + """ + assert 'id' in list(user_data.keys()) + + if commands is None: + pooledConnection = local_db.getPoolConnection() + commands = pydapper.using(pooledConnection) + + # filter: return only the relevant berths to a user, which belong to his assigned ports + user_participant_query = SQLQuery.get_participant_by_user_id() + + # use the user's id to obtain the matching participant + sentinel = object() + participant = commands.query_single_or_default( + user_participant_query, default=sentinel, model=model.Participant, + param={"userid":user_data.get("id")}) + if participant is sentinel: + raise Exception(f"could not find a user with id {user_data.get('id')}") + berths = filter_berths_by_port(berths, participant) + return berths + + +def filter_shipcalls_by_port(shipcalls:list[model.Shipcall], participant:model.Participant)->list[model.Shipcall]: + """ + this function filters a list of shipcalls by the participant's assigned ports. + + Uses: + shipcall.port_id (the port's int id of each shipcall) + Participant.ports (a list of int ids) + + returns: shipcalls (filtered) + """ + shipcalls = [shipcall for shipcall in shipcalls if shipcall.port_id in participant.ports] + return shipcalls + +def filter_shipcalls_by_users_assigned_ports(shipcalls:list[model.Shipcall], user_data:dict, commands=None)->list[model.Shipcall]: + """ + this function uses the user_id to filter a list of shipcalls. Only those shipcalls, which belong to the Participant's assigned + port list are relevant. + + Uses: + shipcall.port_id (the port's int id of each shipcall) + + user_data 'id' to obtain Participant + Participant.ports (a list of int ids) + + returns: shipcalls + """ + assert 'id' in list(user_data.keys()) + + if commands is None: + pooledConnection = local_db.getPoolConnection() + commands = pydapper.using(pooledConnection) + + # filter: return only the relevant shipcalls to a user, which belong to his assigned ports + user_participant_query = SQLQuery.get_participant_by_user_id() + + # use the user's id to obtain the matching participant + sentinel = object() + participant = commands.query_single_or_default( + user_participant_query, default=sentinel, model=model.Participant, + param={"userid":user_data.get("id")}) + if participant is sentinel: + raise Exception(f"could not find a user with id {user_data.get('id')}") + shipcalls = filter_shipcalls_by_port(shipcalls, participant) + return shipcalls diff --git a/src/server/BreCal/impl/berths.py b/src/server/BreCal/impl/berths.py index f00a9e8..0920d71 100644 --- a/src/server/BreCal/impl/berths.py +++ b/src/server/BreCal/impl/berths.py @@ -4,6 +4,7 @@ import pydapper from ..schemas import model from .. import local_db +from BreCal.database.sql_utils import filter_berths_by_users_assigned_ports def GetBerths(options): """ diff --git a/src/server/BreCal/impl/shipcalls.py b/src/server/BreCal/impl/shipcalls.py index 087a552..1891ddd 100644 --- a/src/server/BreCal/impl/shipcalls.py +++ b/src/server/BreCal/impl/shipcalls.py @@ -8,11 +8,12 @@ from .. import local_db from ..services.auth_guard import check_jwt from BreCal.database.update_database import evaluate_shipcall_state +from BreCal.database.sql_utils import filter_shipcalls_by_users_assigned_ports from BreCal.database.sql_queries import create_sql_query_shipcall_get, create_sql_query_shipcall_post, create_sql_query_shipcall_put, create_sql_query_history_post, create_sql_query_history_put, SQLQuery from marshmallow import Schema, fields, ValidationError from BreCal.validators.validation_error import create_validation_error_response -def GetShipcalls(options): +def GetShipcalls(user_data, options): """ No parameters, gets all entries """ @@ -24,8 +25,12 @@ def GetShipcalls(options): # query = SQLQuery.get_shipcalls(options) query = create_sql_query_shipcall_get(options) - data = commands.query(query, model=model.Shipcall.from_query_row, buffered=True) - for shipcall in data: + shipcalls = commands.query(query, model=model.Shipcall.from_query_row, buffered=True) + + # filter: return only the relevant shipcalls to a user, which belong to his assigned ports + shipcalls = filter_shipcalls_by_users_assigned_ports(shipcalls, user_data, commands=commands) + + for shipcall in shipcalls: # participant_query = SQLQuery.get_participants() # participants = commands.query(participant_query, model=dict, param={"shipcall_id" : shipcall.id}, buffered=False) # for record in participants: @@ -35,7 +40,7 @@ def GetShipcalls(options): pa = model.Participant_Assignment(record["participant_id"], record["type"]) shipcall.participants.append(pa) - return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} + return json.dumps(shipcalls, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: logging.error(traceback.format_exc()) @@ -141,7 +146,7 @@ def PostShipcalls(schemaModel): commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]}) # 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=new_id) # new_id (last insert id) refers to the shipcall id + evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id # save history data # TODO: set ETA properly @@ -255,6 +260,9 @@ def PutShipcalls(schemaModel): dquery = "DELETE FROM shipcall_participant_map WHERE id = ?existing_id?" commands.execute(dquery, param={"existing_id" : elem["id"]}) + # re-evaluate the shipcall + evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["id"]) + # save history data # TODO: set ETA properly # query = SQLQuery.create_sql_query_history_put() diff --git a/src/server/BreCal/stubs/shipcall.py b/src/server/BreCal/stubs/shipcall.py index 78aee75..3b4ea4e 100644 --- a/src/server/BreCal/stubs/shipcall.py +++ b/src/server/BreCal/stubs/shipcall.py @@ -14,6 +14,7 @@ def get_shipcall_simple(): shipcall_id = 124 # generate_uuid1_int() ship_id = 5 # generate_uuid1_int() + port_id = 12 eta = base_time+datetime.timedelta(hours=3, minutes=12) role_type = 1 @@ -84,6 +85,7 @@ def get_shipcall_simple(): evaluation_time, evaluation_notifications_sent, time_ref_point, + port_id, created, modified, participants,