From 6349e4a73cbd271f7ed6a35e37329548a9225409 Mon Sep 17 00:00:00 2001 From: Max Metz Date: Mon, 29 Apr 2024 18:50:46 +0200 Subject: [PATCH] implementing more input-validation-functions for shipcalls and ships. Beginning to refactor some of the validation functions into more readable Python classes. --- src/server/BreCal/api/shipcalls.py | 14 +++++--- src/server/BreCal/api/ships.py | 35 +++++++++++++++++-- src/server/BreCal/stubs/shipcall.py | 3 ++ .../BreCal/validators/input_validation.py | 20 +++++++---- .../validators/input_validation_shipcall.py | 0 5 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 src/server/BreCal/validators/input_validation_shipcall.py diff --git a/src/server/BreCal/api/shipcalls.py b/src/server/BreCal/api/shipcalls.py index c1c6e5d..e43f7ec 100644 --- a/src/server/BreCal/api/shipcalls.py +++ b/src/server/BreCal/api/shipcalls.py @@ -4,7 +4,7 @@ from marshmallow import Schema, fields, ValidationError from ..schemas import model from .. import impl from ..services.auth_guard import auth_guard, check_jwt -from BreCal.validators.input_validation import validate_posted_shipcall_data +from BreCal.validators.input_validation import validate_posted_shipcall_data, check_if_user_is_bsmd_type import logging import json @@ -41,9 +41,6 @@ def PostShipcalls(): try: content = request.get_json(force=True) loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True) - logging.log(20, loadedModel) - logging.log(20, "dev. above: loaded model, below: content") - logging.log(20, content) # read the user data from the JWT token (set when login is performed) user_data = check_jwt() @@ -72,6 +69,15 @@ def PutShipcalls(): content = request.get_json(force=True) logging.info(content) loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True) + + # read the user data from the JWT token (set when login is performed) + user_data = check_jwt() + + # check, whether the user belongs to a participant, which is of type ParticipantType.BSMD + # as ParticipantType is an IntFlag, a user belonging to multiple groups is properly evaluated. + is_bsmd = check_if_user_is_bsmd_type(user_data) + if not is_bsmd: + raise ValidationError(f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}") except ValidationError as ex: logging.error(ex) diff --git a/src/server/BreCal/api/ships.py b/src/server/BreCal/api/ships.py index e31147e..5fc3c50 100644 --- a/src/server/BreCal/api/ships.py +++ b/src/server/BreCal/api/ships.py @@ -1,11 +1,14 @@ from flask import Blueprint, request from .. import impl -from ..services.auth_guard import auth_guard -from marshmallow import EXCLUDE +from ..services.auth_guard import auth_guard, check_jwt +from marshmallow import EXCLUDE, ValidationError from ..schemas import model import json import logging +from BreCal.validators.input_validation import check_if_user_is_bsmd_type + + bp = Blueprint('ships', __name__) @bp.route('/ships', methods=['get']) @@ -24,6 +27,15 @@ def GetShips(): def PostShip(): try: + # read the user data from the JWT token (set when login is performed) + user_data = check_jwt() + + # check, whether the user belongs to a participant, which is of type ParticipantType.BSMD + # as ParticipantType is an IntFlag, a user belonging to multiple groups is properly evaluated. + is_bsmd = check_if_user_is_bsmd_type(user_data) + if not is_bsmd: + raise ValidationError(f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}") + content = request.get_json(force=True) loadedModel = model.ShipSchema().load(data=content, many=False, partial=True) except Exception as ex: @@ -39,6 +51,15 @@ def PostShip(): def PutShip(): try: + # read the user data from the JWT token (set when login is performed) + user_data = check_jwt() + + # check, whether the user belongs to a participant, which is of type ParticipantType.BSMD + # as ParticipantType is an IntFlag, a user belonging to multiple groups is properly evaluated. + is_bsmd = check_if_user_is_bsmd_type(user_data) + if not is_bsmd: + raise ValidationError(f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}") + content = request.get_json(force=True) loadedModel = model.ShipSchema().load(data=content, many=False, partial=True, unknown=EXCLUDE) except Exception as ex: @@ -53,8 +74,16 @@ def PutShip(): @auth_guard() # no restriction by role def DeleteShip(): - # TODO check if I am allowed to delete this thing by deriving the participant from the bearer token try: + # read the user data from the JWT token (set when login is performed) + user_data = check_jwt() + + # check, whether the user belongs to a participant, which is of type ParticipantType.BSMD + # as ParticipantType is an IntFlag, a user belonging to multiple groups is properly evaluated. + is_bsmd = check_if_user_is_bsmd_type(user_data) + if not is_bsmd: + raise ValidationError(f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}") + if 'id' in request.args: options = {} options["id"] = request.args.get("id") diff --git a/src/server/BreCal/stubs/shipcall.py b/src/server/BreCal/stubs/shipcall.py index 48c81f7..9efab32 100644 --- a/src/server/BreCal/stubs/shipcall.py +++ b/src/server/BreCal/stubs/shipcall.py @@ -89,12 +89,15 @@ def create_postman_stub_shipcall(): """ this function returns the common stub, which is used to POST data to shipcalls via POSTMAN. However, the stub-function is updated with a dynamic ETA in the future, so the POST-request does not fail. + + Also provides a stub arrival_berth_id, so the POST-request succeeds. """ shipcall = { 'ship_id': 1, 'type': 1, 'eta': (datetime.datetime.now()+datetime.timedelta(hours=3)).isoformat(), 'voyage': '43B', + 'arrival_berth_id':142, 'tug_required': False, 'pilot_required': True, 'flags': 0, diff --git a/src/server/BreCal/validators/input_validation.py b/src/server/BreCal/validators/input_validation.py index 2652f11..048d594 100644 --- a/src/server/BreCal/validators/input_validation.py +++ b/src/server/BreCal/validators/input_validation.py @@ -26,6 +26,10 @@ def check_if_string_has_special_characters(text:str): """ return bool(set(text).difference(ascii_letters + digits)) +def check_if_int_is_valid_flag(value, enum_object): + # e.g., when an IntFlag has the values 1,2,4; the maximum valid value is 7 + max_int = sum([int(val) for val in list(enum_object._value2member_map_.values())]) + return 0 < value <= max_int def get_participant_id_dictionary(): # get all participants @@ -126,11 +130,6 @@ 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""" # #TODO_refactor: this function is pretty complex. One may instead build an object, which calls the methods separately. - import logging - logging.log(20, "dev") - logging.log(20, user_data) - logging.log(20, loadedModel) - logging.log(20, content) ##### Section 1: check user_data ##### # check, whether the user belongs to a participant, which is of type ParticipantType.BSMD # as ParticipantType is an IntFlag, a user belonging to multiple groups is properly evaluated. @@ -205,7 +204,16 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict raise ValidationError(f"providing 'arrival_berth_id' & 'departure_berth_id' is mandatory. Missing key!") if (not eta >= time_now) or (not etd >= time_now) or (not eta >= etd): raise ValidationError(f"'eta' and 'etd' must be in the future. Incorrect datetime provided.") - + + tidal_window_from = loadedModel.get("tidal_window_from", None) + tidal_window_to = loadedModel.get("tidal_window_to", None) + if tidal_window_to is not None: + if not tidal_window_to >= time_now: + raise ValidationError(f"'tidal_window_to' must be in the future. Incorrect datetime provided.") + + if tidal_window_from is not None: + if not tidal_window_from >= time_now: + raise ValidationError(f"'tidal_window_from' must be in the future. Incorrect datetime provided.") # #TODO: len of participants > 0, if agency # * assigned participant for agency diff --git a/src/server/BreCal/validators/input_validation_shipcall.py b/src/server/BreCal/validators/input_validation_shipcall.py new file mode 100644 index 0000000..e69de29