extending the capabilities of InputValidationShipcall and performing unit tests to check proper implementation.
This commit is contained in:
parent
ea5aa132d2
commit
98b8845015
@ -9,6 +9,7 @@ from BreCal.validators.input_validation_shipcall import InputValidationShipcall
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
|
import traceback
|
||||||
|
|
||||||
bp = Blueprint('shipcalls', __name__)
|
bp = Blueprint('shipcalls', __name__)
|
||||||
|
|
||||||
@ -47,16 +48,17 @@ def PostShipcalls():
|
|||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
|
||||||
# validate the posted shipcall data
|
# validate the posted shipcall data
|
||||||
validate_posted_shipcall_data(user_data, loadedModel, content)
|
# validate_posted_shipcall_data(user_data, loadedModel, content)
|
||||||
# InputValidationShipcall.evaluate_post_data(user_data, loadedModel, content)
|
InputValidationShipcall.evaluate_post_data(user_data, loadedModel, content)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
return json.dumps(f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"), 400
|
return json.dumps({"message":f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"}), 400
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
|
logging.error(traceback.format_exc())
|
||||||
print(ex)
|
print(ex)
|
||||||
return json.dumps("bad format"), 400
|
return json.dumps("bad format"), 400
|
||||||
|
|
||||||
@ -69,7 +71,6 @@ def PutShipcalls():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
content = request.get_json(force=True)
|
content = request.get_json(force=True)
|
||||||
logging.info(content)
|
|
||||||
loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True)
|
loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True)
|
||||||
|
|
||||||
# read the user data from the JWT token (set when login is performed)
|
# read the user data from the JWT token (set when login is performed)
|
||||||
@ -85,7 +86,7 @@ def PutShipcalls():
|
|||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
return json.dumps(f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"), 400
|
return json.dumps({"message":f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"}), 400
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def create_sql_query_shipcall_get(options:dict)->str:
|
def create_sql_query_shipcall_get(options:dict)->str:
|
||||||
@ -9,6 +10,7 @@ def create_sql_query_shipcall_get(options:dict)->str:
|
|||||||
options : dict. A dictionary, which must contains the 'past_days' key (int). Determines the range
|
options : dict. A dictionary, which must contains the 'past_days' key (int). Determines the range
|
||||||
by which shipcalls are filtered.
|
by which shipcalls are filtered.
|
||||||
"""
|
"""
|
||||||
|
logging.info(options)
|
||||||
query = ("SELECT s.id as id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
query = ("SELECT s.id as id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||||
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||||
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from .. import local_db
|
|||||||
from ..services.auth_guard import check_jwt
|
from ..services.auth_guard import check_jwt
|
||||||
|
|
||||||
from BreCal.database.update_database import evaluate_shipcall_state
|
from BreCal.database.update_database import evaluate_shipcall_state
|
||||||
from BreCal.database.sql_queries import create_sql_query_shipcall_get, create_sql_query_shipcall_post, create_sql_query_shipcall_put
|
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
|
||||||
|
|
||||||
def GetShipcalls(options):
|
def GetShipcalls(options):
|
||||||
"""
|
"""
|
||||||
@ -142,6 +142,7 @@ def PostShipcalls(schemaModel):
|
|||||||
# save history data
|
# save history data
|
||||||
# TODO: set ETA properly
|
# TODO: set ETA properly
|
||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
# query = create_sql_query_history_post()
|
||||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 1)"
|
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"]})
|
commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||||
|
|
||||||
@ -150,7 +151,7 @@ def PostShipcalls(schemaModel):
|
|||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
return json.dumps(f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"), 400
|
return json.dumps({"message":f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"}), 400
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
@ -261,6 +262,7 @@ def PutShipcalls(schemaModel):
|
|||||||
# save history data
|
# save history data
|
||||||
# TODO: set ETA properly
|
# TODO: set ETA properly
|
||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
# query = create_sql_query_history_put()
|
||||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 2)"
|
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"]})
|
commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||||
|
|
||||||
@ -269,7 +271,7 @@ def PutShipcalls(schemaModel):
|
|||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
return json.dumps(f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"), 400
|
return json.dumps({"message":f"bad format. \nError Messages: {ex.messages}. \nValid Data: {ex.valid_data}"}), 400
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
|
|||||||
@ -22,6 +22,7 @@ from BreCal.validators.input_validation_utils import check_if_user_is_bsmd_type,
|
|||||||
|
|
||||||
def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict):
|
def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict):
|
||||||
"""this function applies more complex validation functions to data, which is sent to a post-request of shipcalls"""
|
"""this function applies more complex validation functions to data, which is sent to a post-request of shipcalls"""
|
||||||
|
# DEPRECATED: this function has been refactored into InputValidationShipcall (see methods for POST and PUT evaluation)
|
||||||
# #TODO_refactor: this function is pretty complex. One may instead build an object, which calls the methods separately.
|
# #TODO_refactor: this function is pretty complex. One may instead build an object, which calls the methods separately.
|
||||||
|
|
||||||
##### Section 1: check user_data #####
|
##### Section 1: check user_data #####
|
||||||
@ -44,7 +45,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
|
|||||||
if not valid_departure_berth_id:
|
if not valid_departure_berth_id:
|
||||||
raise ValidationError(f"provided an invalid departure berth id, which is not found in the database: {loadedModel.get('departure_berth_id', None)}")
|
raise ValidationError(f"provided an invalid departure berth id, which is not found in the database: {loadedModel.get('departure_berth_id', None)}")
|
||||||
|
|
||||||
valid_participant_ids = check_if_participant_ids_are_valid(participant_ids=loadedModel.get("participants",[]))
|
valid_participant_ids = check_if_participant_ids_are_valid(participants=loadedModel.get("participants",[]))
|
||||||
if not valid_participant_ids:
|
if not valid_participant_ids:
|
||||||
raise ValidationError(f"one of the provided participant ids is invalid. Could not find one of these in the database: {loadedModel.get('participants', None)}")
|
raise ValidationError(f"one of the provided participant ids is invalid. Could not find one of these in the database: {loadedModel.get('participants', None)}")
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from BreCal.impl.ships import GetShips
|
|||||||
from BreCal.impl.berths import GetBerths
|
from BreCal.impl.berths import GetBerths
|
||||||
|
|
||||||
from BreCal.database.enums import ParticipantType, ParticipantFlag
|
from BreCal.database.enums import ParticipantType, ParticipantFlag
|
||||||
from BreCal.validators.input_validation_utils import check_if_user_is_bsmd_type, check_if_ship_id_is_valid, check_if_berth_id_is_valid, check_if_participant_ids_are_valid, check_if_string_has_special_characters, get_shipcall_id_dictionary, get_participant_type_from_user_data, check_if_int_is_valid_flag
|
from BreCal.validators.input_validation_utils import check_if_user_is_bsmd_type, check_if_ship_id_is_valid, check_if_berth_id_is_valid, check_if_participant_ids_are_valid, check_if_participant_ids_and_types_are_valid, check_if_string_has_special_characters, get_shipcall_id_dictionary, get_participant_type_from_user_data, check_if_int_is_valid_flag
|
||||||
|
|
||||||
|
|
||||||
class InputValidationShipcall():
|
class InputValidationShipcall():
|
||||||
@ -35,8 +35,8 @@ class InputValidationShipcall():
|
|||||||
checks:
|
checks:
|
||||||
1. permission: only participants that belong to the BSMD group are allowed to POST shipcalls
|
1. permission: only participants that belong to the BSMD group are allowed to POST shipcalls
|
||||||
2. reference checks: all refered objects within the Shipcall must exist
|
2. reference checks: all refered objects within the Shipcall must exist
|
||||||
3. reasonable values: validates the values within the Shipcall
|
3. existance of required fields
|
||||||
4. existance of required fields
|
4. reasonable values: validates the values within the Shipcall
|
||||||
"""
|
"""
|
||||||
# check for permission (only BSMD-type participants)
|
# check for permission (only BSMD-type participants)
|
||||||
InputValidationShipcall.check_user_is_bsmd_type(user_data)
|
InputValidationShipcall.check_user_is_bsmd_type(user_data)
|
||||||
@ -44,14 +44,14 @@ class InputValidationShipcall():
|
|||||||
# check references (referred IDs must exist)
|
# check references (referred IDs must exist)
|
||||||
InputValidationShipcall.check_referenced_ids(loadedModel)
|
InputValidationShipcall.check_referenced_ids(loadedModel)
|
||||||
|
|
||||||
# check for reasonable values in the shipcall fields
|
|
||||||
InputValidationShipcall.check_shipcall_values(loadedModel, content, forbidden_keys=["canceled", "evaluation", "evaluation_message"])
|
|
||||||
|
|
||||||
# POST-request only: check the existance of required fields based on the ShipcallType
|
# POST-request only: check the existance of required fields based on the ShipcallType
|
||||||
InputValidationShipcall.check_required_fields_exist_based_on_type(loadedModel, content)
|
InputValidationShipcall.check_required_fields_exist_based_on_type(loadedModel, content)
|
||||||
|
|
||||||
# POST-request only: check the existance of a participant list, when the user is of type agency
|
# POST-request only: check the existance of a participant list, when the user is of type agency
|
||||||
InputValidationShipcall.check_participant_list_not_empty_when_user_is_agency(user_data, loadedModel)
|
InputValidationShipcall.check_participant_list_not_empty_when_user_is_agency(loadedModel)
|
||||||
|
|
||||||
|
# check for reasonable values in the shipcall fields
|
||||||
|
InputValidationShipcall.check_shipcall_values(loadedModel, content, forbidden_keys=["canceled", "evaluation", "evaluation_message"])
|
||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -62,9 +62,9 @@ class InputValidationShipcall():
|
|||||||
checks:
|
checks:
|
||||||
1. whether the user belongs to participant group type BSMD
|
1. whether the user belongs to participant group type BSMD
|
||||||
2. users of the agency may edit the shipcall, when the shipcall-participant-map entry lists them
|
2. users of the agency may edit the shipcall, when the shipcall-participant-map entry lists them
|
||||||
3. all value-rules of the POST evaluation
|
3. existance of required fields
|
||||||
4. a canceled shipcall may not be changed
|
4. all value-rules of the POST evaluation
|
||||||
5. existance of required fields
|
5. a canceled shipcall may not be changed
|
||||||
"""
|
"""
|
||||||
# check for permission (only BSMD-type participants)
|
# check for permission (only BSMD-type participants)
|
||||||
InputValidationShipcall.check_user_is_bsmd_type(user_data)
|
InputValidationShipcall.check_user_is_bsmd_type(user_data)
|
||||||
@ -72,14 +72,14 @@ class InputValidationShipcall():
|
|||||||
# check, whether an agency is listed in the shipcall-participant-map
|
# check, whether an agency is listed in the shipcall-participant-map
|
||||||
# InputValidationShipcall.check_agency_in_shipcall_participant_map() # args?
|
# InputValidationShipcall.check_agency_in_shipcall_participant_map() # args?
|
||||||
|
|
||||||
|
# the ID field is required, all missing fields will be ignored in the update
|
||||||
|
InputValidationShipcall.check_required_fields_of_put_request(content)
|
||||||
|
|
||||||
# check for reasonable values in the shipcall fields and checks for forbidden keys. Note: 'canceled' is allowed in PUT-requests.
|
# check for reasonable values in the shipcall fields and checks for forbidden keys. Note: 'canceled' is allowed in PUT-requests.
|
||||||
InputValidationShipcall.check_shipcall_values(loadedModel, content, forbidden_keys=["evaluation", "evaluation_message"])
|
InputValidationShipcall.check_shipcall_values(loadedModel, content, forbidden_keys=["evaluation", "evaluation_message"])
|
||||||
|
|
||||||
# a canceled shipcall cannot be selected
|
# a canceled shipcall cannot be selected
|
||||||
InputValidationShipcall.check_shipcall_is_canceled(loadedModel, content)
|
InputValidationShipcall.check_shipcall_is_canceled(loadedModel, content)
|
||||||
|
|
||||||
# the ID field is required, all missing fields will be ignored in the update
|
|
||||||
InputValidationShipcall.check_required_fields_of_put_request(content)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -136,7 +136,7 @@ class InputValidationShipcall():
|
|||||||
ship_id = loadedModel.get("ship_id", None)
|
ship_id = loadedModel.get("ship_id", None)
|
||||||
arrival_berth_id = loadedModel.get("arrival_berth_id", None)
|
arrival_berth_id = loadedModel.get("arrival_berth_id", None)
|
||||||
departure_berth_id = loadedModel.get("departure_berth_id", None)
|
departure_berth_id = loadedModel.get("departure_berth_id", None)
|
||||||
participant_ids = loadedModel.get("participants",[])
|
participants = loadedModel.get("participants",[])
|
||||||
|
|
||||||
valid_ship_id = check_if_ship_id_is_valid(ship_id=ship_id)
|
valid_ship_id = check_if_ship_id_is_valid(ship_id=ship_id)
|
||||||
if not valid_ship_id:
|
if not valid_ship_id:
|
||||||
@ -150,11 +150,14 @@ class InputValidationShipcall():
|
|||||||
if not valid_departure_berth_id:
|
if not valid_departure_berth_id:
|
||||||
raise ValidationError(f"provided an invalid departure berth id, which is not found in the database: {departure_berth_id}")
|
raise ValidationError(f"provided an invalid departure berth id, which is not found in the database: {departure_berth_id}")
|
||||||
|
|
||||||
valid_participant_ids = check_if_participant_ids_are_valid(participant_ids=participant_ids)
|
valid_participant_ids = check_if_participant_ids_are_valid(participants=participants)
|
||||||
if not valid_participant_ids:
|
if not valid_participant_ids:
|
||||||
raise ValidationError(f"one of the provided participant ids is invalid. Could not find one of these in the database: {participant_ids}")
|
raise ValidationError(f"one of the provided participant ids are invalid. Could not find one of these in the database: {participants}")
|
||||||
return
|
|
||||||
|
valid_participant_types = check_if_participant_ids_and_types_are_valid(participants=participants)
|
||||||
|
if not valid_participant_types:
|
||||||
|
raise ValidationError(f"every participant id and type should be listed only once. Found multiple entries for one of the participants.")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_forbidden_arguments(content:dict, forbidden_keys=["canceled", "evaluation", "evaluation_message"]):
|
def check_forbidden_arguments(content:dict, forbidden_keys=["canceled", "evaluation", "evaluation_message"]):
|
||||||
"""
|
"""
|
||||||
@ -175,11 +178,15 @@ class InputValidationShipcall():
|
|||||||
depending on the ShipcallType, some fields are *required* in a POST-request
|
depending on the ShipcallType, some fields are *required* in a POST-request
|
||||||
"""
|
"""
|
||||||
type_ = loadedModel.get("type", int(ShipcallType.undefined))
|
type_ = loadedModel.get("type", int(ShipcallType.undefined))
|
||||||
|
ship_id = content.get("ship_id", None)
|
||||||
eta = content.get("eta", None)
|
eta = content.get("eta", None)
|
||||||
etd = content.get("etd", None)
|
etd = content.get("etd", None)
|
||||||
arrival_berth_id = content.get("arrival_berth_id", None)
|
arrival_berth_id = content.get("arrival_berth_id", None)
|
||||||
departure_berth_id = content.get("departure_berth_id", None)
|
departure_berth_id = content.get("departure_berth_id", None)
|
||||||
|
|
||||||
|
if ship_id is None:
|
||||||
|
raise ValidationError(f"providing 'ship_id' is mandatory. Missing key!")
|
||||||
|
|
||||||
if int(type_)==int(ShipcallType.undefined):
|
if int(type_)==int(ShipcallType.undefined):
|
||||||
raise ValidationError(f"providing 'type' is mandatory. Missing key!")
|
raise ValidationError(f"providing 'type' is mandatory. Missing key!")
|
||||||
|
|
||||||
@ -244,16 +251,16 @@ class InputValidationShipcall():
|
|||||||
if int(type_)==int(ShipcallType.undefined):
|
if int(type_)==int(ShipcallType.undefined):
|
||||||
raise ValidationError(f"providing 'type' is mandatory. Missing key!")
|
raise ValidationError(f"providing 'type' is mandatory. Missing key!")
|
||||||
elif int(type_)==int(ShipcallType.arrival):
|
elif int(type_)==int(ShipcallType.arrival):
|
||||||
if not eta >= time_now:
|
if not eta > time_now:
|
||||||
raise ValidationError(f"'eta' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}.")
|
raise ValidationError(f"'eta' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}.")
|
||||||
elif int(type_)==int(ShipcallType.departure):
|
elif int(type_)==int(ShipcallType.departure):
|
||||||
if not etd >= time_now:
|
if not etd > time_now:
|
||||||
raise ValidationError(f"'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETD: {etd}.")
|
raise ValidationError(f"'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETD: {etd}.")
|
||||||
elif int(type_)==int(ShipcallType.shifting):
|
elif int(type_)==int(ShipcallType.shifting):
|
||||||
if (not eta >= time_now) or (not etd >= time_now):
|
if (not eta > time_now) or (not etd > time_now):
|
||||||
raise ValidationError(f"'eta' and 'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}. ETD: {etd}")
|
raise ValidationError(f"'eta' and 'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}. ETD: {etd}")
|
||||||
if (not eta >= etd):
|
if (not etd > eta):
|
||||||
raise ValidationError(f"'etd' must be larger than 'eta'. The ship cannot depart, before it has arrived. Found: ETA {eta}, ETA: {etd}")
|
raise ValidationError(f"'etd' must be larger than 'eta'. The ship cannot depart, before it has arrived. Found: ETA {eta}, ETD: {etd}")
|
||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -272,18 +279,15 @@ class InputValidationShipcall():
|
|||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_participant_list_not_empty_when_user_is_agency(user_data, loadedModel):
|
def check_participant_list_not_empty_when_user_is_agency(loadedModel):
|
||||||
"""
|
"""
|
||||||
participant types use an IntFlag to assign multiple roles to a user. When a user is assigned to the
|
For each POST request, one of the participants in the list must be assigned as a ParticipantType.AGENCY
|
||||||
AGENCY role, the user must provide a non-empty list of participants in POST-requests.
|
|
||||||
"""
|
"""
|
||||||
participant_type = get_participant_type_from_user_data(user_data)
|
participants = loadedModel.get("participants", [])
|
||||||
|
is_agency_participant = [ParticipantType.AGENCY in ParticipantType(participant.get("type")) for participant in participants]
|
||||||
|
|
||||||
if int(ParticipantType.AGENCY) in int(participant_type):
|
if not any(is_agency_participant):
|
||||||
participants = loadedModel.get("participants",[])
|
raise ValidationError(f"One of the assigned participants *must* be of type 'ParticipantType.AGENCY'. Found list of participants: {participants}")
|
||||||
|
|
||||||
if len(participants)==0:
|
|
||||||
raise ValidationError(f"A user of type 'ParticipantType.AGENCY' is required to provide a list of valid participants.")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import logging
|
||||||
import json
|
import json
|
||||||
from string import ascii_letters, digits
|
from string import ascii_letters, digits
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
from BreCal.impl.participant import GetParticipant
|
from BreCal.impl.participant import GetParticipant
|
||||||
from BreCal.impl.ships import GetShips
|
from BreCal.impl.ships import GetShips
|
||||||
@ -104,9 +106,16 @@ def check_if_berth_id_is_valid(berth_id):
|
|||||||
berth_id_is_valid = berth_id in list(berths.keys())
|
berth_id_is_valid = berth_id in list(berths.keys())
|
||||||
return berth_id_is_valid
|
return berth_id_is_valid
|
||||||
|
|
||||||
def check_if_participant_id_is_valid(participant_id):
|
def check_if_participant_id_is_valid(participant:dict):
|
||||||
"""check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a shipcall POST-request, does not have to include all IDs at once"""
|
"""
|
||||||
|
check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a shipcall POST-request, does not have to include all IDs at once
|
||||||
|
|
||||||
|
Following the common BreCal.schemas.model.ParticipantAssignmentSchema, a participant dictionary contains the keys:
|
||||||
|
'participant_id' : int
|
||||||
|
'type' : ParticipantType
|
||||||
|
"""
|
||||||
# #TODO1: Daniel Schick: 'types may only appear once and must not include type "BSMD"'
|
# #TODO1: Daniel Schick: 'types may only appear once and must not include type "BSMD"'
|
||||||
|
participant_id = participant.get("participant_id", None)
|
||||||
|
|
||||||
if participant_id is None:
|
if participant_id is None:
|
||||||
return True
|
return True
|
||||||
@ -118,13 +127,37 @@ def check_if_participant_id_is_valid(participant_id):
|
|||||||
participant_id_is_valid = participant_id in list(participants.keys())
|
participant_id_is_valid = participant_id in list(participants.keys())
|
||||||
return participant_id_is_valid
|
return participant_id_is_valid
|
||||||
|
|
||||||
def check_if_participant_ids_are_valid(participant_ids):
|
def check_if_participant_ids_are_valid(participants:list[dict]):
|
||||||
|
"""
|
||||||
|
|
||||||
|
args:
|
||||||
|
participants (list of participant-elements)
|
||||||
|
Following the common BreCal.schemas.model.ParticipantAssignmentSchema, a participant dictionary contains the keys:
|
||||||
|
'participant_id' : int
|
||||||
|
'type' : ParticipantType
|
||||||
|
"""
|
||||||
# check each participant id individually
|
# check each participant id individually
|
||||||
valid_participant_ids = [check_if_participant_id_is_valid(participant_id) for participant_id in participant_ids]
|
valid_participant_ids = [check_if_participant_id_is_valid(participant) for participant in participants]
|
||||||
|
|
||||||
# boolean check, whether all participant ids are valid
|
# boolean check, whether all participant ids are valid
|
||||||
return all(valid_participant_ids)
|
return all(valid_participant_ids)
|
||||||
|
|
||||||
|
def check_if_participant_ids_and_types_are_valid(participants:list[dict[str,int]]):
|
||||||
|
# creates a Counter object, which counts the number of unique elements
|
||||||
|
# key of counter: type, value of counter: number of listings in 'participants'
|
||||||
|
# e.g., {1: 4, 2: 1, 8: 1} (type 1 occurs 4 times in this example)
|
||||||
|
counter_type = Counter([participant.get("type") for participant in participants])
|
||||||
|
counter_id = Counter([participant.get("type") for participant in participants])
|
||||||
|
|
||||||
|
# obtains the maximum count from the counter's values
|
||||||
|
max_count_type = max(list(counter_type.values())) if len(list(counter_type.values()))>0 else 0
|
||||||
|
max_count_ids = max(list(counter_id.values())) if len(list(counter_id.values()))>0 else 0
|
||||||
|
|
||||||
|
# when 0 or 1 count for the participant ids or types, return true. Return false, when there is more than one entry.
|
||||||
|
return max_count_type <= 1 and max_count_ids <= 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_if_string_has_special_characters(text:str):
|
def check_if_string_has_special_characters(text:str):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user