From 5ce866936dde6feba8425fb84ef3bfbe4cc93cc9 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 16 Sep 2024 14:17:30 +0200 Subject: [PATCH] unified return structure to use error_field instead of message key to correspond to API specification --- .../brecal_utils/request_status_code.py | 44 +++++++++---------- src/server/BreCal/impl/berths.py | 4 +- src/server/BreCal/impl/history.py | 2 +- src/server/BreCal/impl/login.py | 9 ++-- src/server/BreCal/impl/notifications.py | 2 +- src/server/BreCal/impl/participant.py | 12 ++--- src/server/BreCal/impl/ports.py | 2 +- src/server/BreCal/impl/shipcalls.py | 22 +++++----- src/server/BreCal/impl/ships.py | 10 ++--- src/server/BreCal/impl/times.py | 10 ++--- src/server/BreCal/impl/user.py | 4 +- src/server/BreCal/services/auth_guard.py | 4 +- .../BreCal/validators/validation_error.py | 2 +- 13 files changed, 64 insertions(+), 63 deletions(-) diff --git a/src/server/BreCal/brecal_utils/request_status_code.py b/src/server/BreCal/brecal_utils/request_status_code.py index c3d72ea..a6401d3 100644 --- a/src/server/BreCal/brecal_utils/request_status_code.py +++ b/src/server/BreCal/brecal_utils/request_status_code.py @@ -22,15 +22,15 @@ def get_request_code(code_id): class RequestStatusCode(ABC): def __init__(self): return - + @abstractmethod def __call__(self, data): raise NotImplementedError("any default status code object must be callable") - + @abstractmethod def status_code(self): raise NotImplementedError("any default status code object should return an integer") - + @abstractmethod def response(self, data): raise NotImplementedError("the response method should return a binary json object. typically, json.dumps is used") @@ -38,7 +38,7 @@ class RequestStatusCode(ABC): def headers(self): return {'Content-Type': 'application/json; charset=utf-8'} - + class RequestCode_HTTP_200_OK(RequestStatusCode): def __init__(self) -> None: @@ -46,13 +46,13 @@ class RequestCode_HTTP_200_OK(RequestStatusCode): def __call__(self, data): return (self.response(data), self.status_code(), self.headers()) - + def status_code(self): return 200 - + def response(self, data): return json.dumps(data, default=obj_dict) - + class RequestCode_HTTP_201_CREATED(RequestStatusCode): def __init__(self) -> None: @@ -60,10 +60,10 @@ class RequestCode_HTTP_201_CREATED(RequestStatusCode): def __call__(self, data): return (self.response(data), self.status_code(), self.headers()) - + def status_code(self): return 201 - + def response(self, new_id): return json.dumps({"id":new_id}) @@ -74,10 +74,10 @@ class RequestCode_HTTP_400_BAD_REQUEST(RequestStatusCode): def __call__(self, data): return (self.response(data), self.status_code(), self.headers()) - + def status_code(self): return 400 - + def response(self, data): return json.dumps(data) @@ -88,15 +88,15 @@ class RequestCode_HTTP_403_FORBIDDEN(RequestStatusCode): def __call__(self, data): return (self.response(data), self.status_code(), self.headers()) - + def status_code(self): return 403 - + def response(self, message="invalid credentials"): result = {} - result["message"] = message + result["error_field"] = message return json.dumps(result) - + class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode): def __init__(self) -> None: @@ -104,13 +104,13 @@ class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode): def __call__(self, data): return (self.response(data), self.status_code(), self.headers()) - + def status_code(self): return 404 - + def response(self, message="no such record"): result = {} - result["message"] = message + result["error_field"] = message return json.dumps(result) @@ -120,12 +120,12 @@ class RequestCode_HTTP_500_INTERNAL_SERVER_ERROR(RequestStatusCode): def __call__(self, data): return (self.response(data), self.status_code(), self.headers()) - + def status_code(self): return 500 - + def response(self, message="credential lookup mismatch"): result = {} - result["message"] = message + result["error_field"] = message return json.dumps(result) - + diff --git a/src/server/BreCal/impl/berths.py b/src/server/BreCal/impl/berths.py index aefdd87..0eaa7df 100644 --- a/src/server/BreCal/impl/berths.py +++ b/src/server/BreCal/impl/berths.py @@ -13,7 +13,7 @@ def GetBerths(options): try: pooledConnection = local_db.getPoolConnection() commands = pydapper.using(pooledConnection) - + # only load berths to ports that the participant is assigned to query = ("SELECT id, name, `lock`, owner_id, port_id, authority_id, created, modified, deleted FROM berth WHERE " + "deleted = 0 AND + " @@ -26,7 +26,7 @@ def GetBerths(options): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500 finally: diff --git a/src/server/BreCal/impl/history.py b/src/server/BreCal/impl/history.py index 53f159c..08cb06e 100644 --- a/src/server/BreCal/impl/history.py +++ b/src/server/BreCal/impl/history.py @@ -35,7 +35,7 @@ def GetHistory(options): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps("call failed"), 500 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 66e709b..949e04a 100644 --- a/src/server/BreCal/impl/login.py +++ b/src/server/BreCal/impl/login.py @@ -21,7 +21,7 @@ def GetUser(options): "api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, created, modified FROM user " + "WHERE user_name = ?username? OR user_email = ?username?", model=model.User, param={"username" : options["username"]}) - + if len(data) == 1: if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")): result = { @@ -39,18 +39,19 @@ def GetUser(options): if len(data) > 1: result = {} - result["message"] = "credential lookup mismatch" + result["error_field"] = "credential lookup mismatch" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} result = {} - result["message"] = "invalid credentials" + result["error_field"] = "invalid credentials" return json.dumps(result), 403, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: logging.error(ex) print(ex) result = {} - result["message"] = "call failed: " + str(ex) + result["error_field"] = "call failed" + result["error_description"] = str(ex) return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: diff --git a/src/server/BreCal/impl/notifications.py b/src/server/BreCal/impl/notifications.py index 2f0014b..0fc39c7 100644 --- a/src/server/BreCal/impl/notifications.py +++ b/src/server/BreCal/impl/notifications.py @@ -27,7 +27,7 @@ def GetNotifications(options): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} 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 4e38031..50ba344 100644 --- a/src/server/BreCal/impl/participant.py +++ b/src/server/BreCal/impl/participant.py @@ -10,7 +10,7 @@ def GetParticipant(options): """ :param options: A dictionary containing all the paramters for the Operations options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call. - """ + """ try: pooledConnection = local_db.getPoolConnection() @@ -22,19 +22,19 @@ def GetParticipant(options): "INNER JOIN user u WHERE u.participant_id = p.id and u.id = %d") % options["user_id"] data = commands.query(query, model=model.Participant) else: - # query = SQLQuery.get_participants() + # query = SQLQuery.get_participants() # list only participants that are assigned to the same ports than participant of caller query = ("SELECT p.id as id, name, street, postal_code, city, type, flags, p.created, p.modified, p.deleted " + - "FROM participant p " + + "FROM participant p " + "JOIN participant_port_map ON p.id = participant_port_map.participant_id " + "WHERE participant_port_map.port_id IN " + "(SELECT port_id FROM participant_port_map where participant_id = %d) " + "GROUP BY id " + "ORDER BY p.name") % options["participant_id"] - + data = commands.query(query, model=model.Participant) - for participant in data: + for participant in data: port_query = "SELECT port_id FROM participant_port_map WHERE participant_id=?id?"; for record in commands.query(port_query, model=model.Port_Assignment, param={"id" : participant.id}, buffered=False): pa = model.Port_Assignment(record.port_id) @@ -46,7 +46,7 @@ def GetParticipant(options): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps("call failed"), 500 finally: diff --git a/src/server/BreCal/impl/ports.py b/src/server/BreCal/impl/ports.py index ba448bf..0a721ec 100644 --- a/src/server/BreCal/impl/ports.py +++ b/src/server/BreCal/impl/ports.py @@ -21,7 +21,7 @@ def GetPorts(token): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500 finally: diff --git a/src/server/BreCal/impl/shipcalls.py b/src/server/BreCal/impl/shipcalls.py index 65bb000..087a552 100644 --- a/src/server/BreCal/impl/shipcalls.py +++ b/src/server/BreCal/impl/shipcalls.py @@ -42,7 +42,7 @@ def GetShipcalls(options): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: @@ -52,8 +52,8 @@ def GetShipcalls(options): def PostShipcalls(schemaModel): """ - This function *executes* a post-request for shipcalls. The function is accessible as part of an API route. - + This function *executes* a post-request for shipcalls. The function is accessible as part of an API route. + The common sequence is: a) issue a request to the Flask API b) BreCal.api.shipcalls.PostShipcalls, to verify the incoming request (which includes an authentification guard) @@ -62,8 +62,8 @@ def PostShipcalls(schemaModel): :param schemaModel: The deserialized dict of the request e.g., { - 'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19), - 'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0, + 'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19), + 'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0, 'pier_side': False, 'bunkering': True, 'recommended_tugs': 2, 'type_value': 1, 'evaluation_value': 0} } """ @@ -89,9 +89,9 @@ def PostShipcalls(schemaModel): if key == "evaluation": continue if key == "evaluation_message": - continue + continue if key == "type_value": - continue + continue if key == "evaluation_value": continue if isNotFirst: @@ -151,7 +151,7 @@ def PostShipcalls(schemaModel): commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]}) return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'} - + except ValidationError as ex: return create_validation_error_response(ex, status_code=400, create_log=True) @@ -160,7 +160,7 @@ def PostShipcalls(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: @@ -262,7 +262,7 @@ def PutShipcalls(schemaModel): commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]}) return json.dumps({"id" : schemaModel["id"]}), 200 - + except ValidationError as ex: return create_validation_error_response(ex, status_code=400, create_log=True) @@ -271,7 +271,7 @@ def PutShipcalls(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: diff --git a/src/server/BreCal/impl/ships.py b/src/server/BreCal/impl/ships.py index 0733071..93a5d4d 100644 --- a/src/server/BreCal/impl/ships.py +++ b/src/server/BreCal/impl/ships.py @@ -25,7 +25,7 @@ def GetShips(token): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: @@ -91,7 +91,7 @@ def PostShip(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} @@ -133,7 +133,7 @@ def PutShip(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} @@ -157,12 +157,12 @@ def DeleteShip(options): return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} result = {} - result["message"] = "no such record" + result["error_field"] = "no such record" return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} \ No newline at end of file diff --git a/src/server/BreCal/impl/times.py b/src/server/BreCal/impl/times.py index a054989..e12f624 100644 --- a/src/server/BreCal/impl/times.py +++ b/src/server/BreCal/impl/times.py @@ -35,7 +35,7 @@ def GetTimes(options): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} @@ -104,7 +104,7 @@ def PostTimes(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: @@ -164,7 +164,7 @@ def PutTimes(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: @@ -195,14 +195,14 @@ def DeleteTimes(options): return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} result = {} - result["message"] = "no such record" + result["error_field"] = "no such record" return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'} except Exception as ex: logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: diff --git a/src/server/BreCal/impl/user.py b/src/server/BreCal/impl/user.py index 733998c..92dc02d 100644 --- a/src/server/BreCal/impl/user.py +++ b/src/server/BreCal/impl/user.py @@ -63,7 +63,7 @@ def PutUser(schemaModel): commands.execute(query, param={"password_hash" : password_hash, "id" : schemaModel["id"]}) else: result = {} - result["message"] = "old password invalid" + result["error_field"] = "old password invalid" return json.dumps(result), 400, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps({"id" : schemaModel["id"]}), 200 @@ -72,7 +72,7 @@ def PutUser(schemaModel): logging.error(ex) print(ex) result = {} - result["message"] = "call failed" + result["error_field"] = "call failed" return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} finally: diff --git a/src/server/BreCal/services/auth_guard.py b/src/server/BreCal/services/auth_guard.py index 9bd27c6..b69ff0e 100644 --- a/src/server/BreCal/services/auth_guard.py +++ b/src/server/BreCal/services/auth_guard.py @@ -25,9 +25,9 @@ def auth_guard(role=None): try: user_data = check_jwt() except Exception as e: - return json.dumps({"message" : f'{e}', "status": 401}), 401 + return json.dumps({"error_field" : f'{e}', "status": 401}), 401 if role and role not in user_data['roles']: - return json.dumps({"message": 'Authorization required.', "status" : 403}), 403 + return json.dumps({"error_field": 'Authorization required.', "status" : 403}), 403 # get on to original route return route_function(*args, **kwargs) decorated_function.__name__ = route_function.__name__ diff --git a/src/server/BreCal/validators/validation_error.py b/src/server/BreCal/validators/validation_error.py index 823a924..5a4ab7d 100644 --- a/src/server/BreCal/validators/validation_error.py +++ b/src/server/BreCal/validators/validation_error.py @@ -77,7 +77,7 @@ def create_werkzeug_error_response(ex:Forbidden, status_code:int=403, create_log def create_dynamic_exception_response(ex, status_code:int=400, message:typing.Optional[str]=None, create_log:bool=True): message = repr(ex) if message is None else message json_response = create_default_json_response_format(error_field="Exception", error_description=message) - json_response["message"] = "call failed" + json_response["error_field"] = "call failed" serialized_response = json.dumps(json_response, default=str)