340 lines
15 KiB
Python
340 lines
15 KiB
Python
import json
|
|
import logging
|
|
import traceback
|
|
import pydapper
|
|
|
|
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.database.sql_utils import get_notification_for_shipcall_and_type, get_ship_data_for_id
|
|
from BreCal.database.sql_queries import create_sql_query_shipcall_get
|
|
from marshmallow import Schema, fields, ValidationError
|
|
from BreCal.validators.validation_error import create_validation_error_response
|
|
|
|
def GetShipcalls(options):
|
|
"""
|
|
No parameters, gets all entries
|
|
"""
|
|
|
|
try:
|
|
|
|
pooledConnection = local_db.getPoolConnection()
|
|
commands = pydapper.using(pooledConnection)
|
|
# 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:
|
|
# participant_query = SQLQuery.get_participants()
|
|
# participants = commands.query(participant_query, model=dict, param={"shipcall_id" : shipcall.id}, buffered=False)
|
|
# for record in participants:
|
|
participant_query = "SELECT participant_id, type FROM shipcall_participant_map WHERE shipcall_id=?shipcall_id?";
|
|
for record in commands.query(participant_query, model=dict, param={"shipcall_id" : shipcall.id}, buffered=False):
|
|
# model.Participant_Assignment = model.Participant_Assignment()
|
|
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'}
|
|
|
|
except Exception as ex:
|
|
logging.error(traceback.format_exc())
|
|
logging.error(ex)
|
|
print(ex)
|
|
result = {}
|
|
result["error_field"] = "call failed"
|
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
|
|
|
finally:
|
|
if pooledConnection is not None:
|
|
pooledConnection.close()
|
|
|
|
|
|
def PostShipcalls(schemaModel):
|
|
"""
|
|
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)
|
|
c) BreCal.impl.shipcalls.PostShipcalls, to execute the incoming request
|
|
|
|
: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,
|
|
'pier_side': False, 'bunkering': True, 'recommended_tugs': 2, 'type_value': 1, 'evaluation_value': 0}
|
|
}
|
|
"""
|
|
|
|
# This creates a *new* entry
|
|
try:
|
|
|
|
pooledConnection = local_db.getPoolConnection()
|
|
commands = pydapper.using(pooledConnection)
|
|
|
|
# query = SQLQuery.get_shipcall_post(schemaModel) # create_sql_query_shipcall_post(schemaModel)
|
|
|
|
query = "INSERT INTO shipcall ("
|
|
isNotFirst = False
|
|
for key in schemaModel.keys():
|
|
if key == "id":
|
|
continue
|
|
if key == "participants":
|
|
continue
|
|
if key == "created":
|
|
continue
|
|
if key == "modified":
|
|
continue
|
|
if key == "evaluation":
|
|
continue
|
|
if key == "evaluation_message":
|
|
continue
|
|
if key == "type_value":
|
|
continue
|
|
if key == "evaluation_value":
|
|
continue
|
|
if isNotFirst:
|
|
query += ","
|
|
isNotFirst = True
|
|
query += key
|
|
query += ") VALUES ("
|
|
isNotFirst = False
|
|
for key in schemaModel.keys():
|
|
param_key = key
|
|
if key == "id":
|
|
continue
|
|
if key == "participants":
|
|
continue
|
|
if key == "created":
|
|
continue
|
|
if key == "modified":
|
|
continue
|
|
if key == "evaluation":
|
|
continue
|
|
if key == "evaluation_message":
|
|
continue
|
|
if key == "type":
|
|
param_key = "type_value"
|
|
if key == "type_value":
|
|
continue
|
|
if key == "evaluation":
|
|
param_key = "evaluation_value"
|
|
if key == "evaluation_value":
|
|
continue
|
|
if isNotFirst:
|
|
query += ","
|
|
isNotFirst = True
|
|
query += "?" + param_key + "?"
|
|
query += ")"
|
|
commands.execute(query, schemaModel)
|
|
|
|
# lquery = SQLQuery.get_shipcall_post_last_insert_id()
|
|
# new_id = commands.execute_scalar(lquery)
|
|
new_id = commands.execute_scalar("select last_insert_id()")
|
|
|
|
shipdata = get_ship_data_for_id(schemaModel["ship_id"])
|
|
message = shipdata['name']
|
|
if "type_value" in schemaModel:
|
|
match schemaModel["type_value"]:
|
|
case 1:
|
|
message += " [ARRIVAL]"
|
|
case 2:
|
|
message += " [DEPARTURE]"
|
|
case 3:
|
|
message += " [SHIFTING]"
|
|
|
|
|
|
# add participant assignments if we have a list of participants
|
|
if 'participants' in schemaModel:
|
|
# pquery = SQLQuery.get_shipcall_post_update_shipcall_participant_map()
|
|
pquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
|
nquery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 1, ?message?)" # type = 1 is assignment
|
|
|
|
for participant_assignment in schemaModel["participants"]:
|
|
commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
|
commands.execute(nquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "message" : message})
|
|
|
|
# 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
|
|
|
|
# save history data
|
|
# TODO: set ETA properly
|
|
user_data = check_jwt()
|
|
# query = SQLQuery.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)"
|
|
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)
|
|
|
|
except Exception as ex:
|
|
logging.error(traceback.format_exc())
|
|
logging.error(ex)
|
|
print(ex)
|
|
result = {}
|
|
result["error_field"] = "call failed"
|
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
|
|
|
finally:
|
|
if pooledConnection is not None:
|
|
pooledConnection.close()
|
|
|
|
|
|
def PutShipcalls(schemaModel):
|
|
"""
|
|
|
|
:param schemaModel: The deserialized dict of the request
|
|
"""
|
|
|
|
# This updates an *existing* entry
|
|
try:
|
|
|
|
pooledConnection = local_db.getPoolConnection()
|
|
commands = pydapper.using(pooledConnection)
|
|
|
|
user_data = check_jwt()
|
|
|
|
# test if object to update is found
|
|
|
|
sentinel = object()
|
|
|
|
theshipcall = commands.query_single_or_default("SELECT * FROM shipcall where id = ?id?", sentinel, param={"id" : schemaModel["id"]})
|
|
if theshipcall is sentinel:
|
|
pooledConnection.close()
|
|
return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
|
|
|
was_canceled = theshipcall["canceled"]
|
|
|
|
# query = SQLQuery.get_shipcall_put(schemaModel)
|
|
query = "UPDATE shipcall SET "
|
|
isNotFirst = False
|
|
for key in schemaModel.keys():
|
|
param_key = key
|
|
if key == "id":
|
|
continue
|
|
if key == "participants":
|
|
continue
|
|
if key == "created":
|
|
continue
|
|
if key == "modified":
|
|
continue
|
|
if key == "evaluation":
|
|
continue
|
|
if key == "evaluation_message":
|
|
continue
|
|
if key == "type":
|
|
param_key = "type_value"
|
|
if key == "type_value":
|
|
continue
|
|
if key == "evaluation":
|
|
param_key = "evaluation_value"
|
|
if key == "evaluation_value":
|
|
continue
|
|
if isNotFirst:
|
|
query += ", "
|
|
isNotFirst = True
|
|
query += key + " = ?" + param_key + "? "
|
|
|
|
query += "WHERE id = ?id?"
|
|
|
|
affected_rows = commands.execute(query, param=schemaModel)
|
|
|
|
shipdata = get_ship_data_for_id(schemaModel["ship_id"])
|
|
message = shipdata['name']
|
|
if "type_value" in schemaModel:
|
|
match schemaModel["type_value"]:
|
|
case 1:
|
|
message += " [ARRIVAL]"
|
|
case 2:
|
|
message += " [DEPARTURE]"
|
|
case 3:
|
|
message += " [SHIFTING]"
|
|
|
|
# pquery = SQLQuery.get_shipcall_participant_map_by_shipcall_id()
|
|
pquery = "SELECT id, participant_id, type FROM shipcall_participant_map where shipcall_id = ?id?"
|
|
pdata = commands.query(pquery,param={"id" : schemaModel["id"]}) # existing list of assignments
|
|
|
|
# loop across passed participant ids, creating entries for those not present in pdata
|
|
|
|
existing_notifications = get_notification_for_shipcall_and_type(schemaModel["id"], 1) # type = 1 is assignment
|
|
|
|
for participant_assignment in schemaModel["participants"]:
|
|
found_participant = False
|
|
for elem in pdata:
|
|
if elem["participant_id"] == participant_assignment["participant_id"] and elem["type"] == participant_assignment["type"]:
|
|
found_participant = True
|
|
break
|
|
if not found_participant:
|
|
# nquery = SQLQuery.get_shipcall_post_update_shipcall_participant_map()
|
|
spquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
|
commands.execute(spquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
|
|
|
# create a notification but only if there is no existing notification in level 0
|
|
found_notification = False
|
|
for existing_notification in existing_notifications:
|
|
if existing_notification["participant_id"] == participant_assignment["participant_id"] and existing_notification["level"] == 1:
|
|
found_notification = True
|
|
break
|
|
if not found_notification:
|
|
nquery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 1, ?message?)" # type = 1 is assignment
|
|
commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "message" : message})
|
|
|
|
# loop across existing pdata entries, deleting those not present in participant list
|
|
for elem in pdata:
|
|
found_participant = False
|
|
for participant_assignment in schemaModel["participants"]:
|
|
if(participant_assignment["participant_id"] == elem["participant_id"] and participant_assignment["type"] == elem["type"]):
|
|
found_participant = True
|
|
break;
|
|
if not found_participant:
|
|
# dquery = SQLQuery.get_shipcall_participant_map_delete_by_id()
|
|
dquery = "DELETE FROM shipcall_participant_map WHERE id = ?existing_id?"
|
|
commands.execute(dquery, param={"existing_id" : elem["id"]})
|
|
# TODO: Create un-assignment notification but only if level > 0 else delete existing notification
|
|
for existing_notification in existing_notifications:
|
|
if existing_notification["participant_id"] == elem["participant_id"]:
|
|
if existing_notification["level"] == 0:
|
|
nquery = "DELETE FROM notification WHERE id = ?nid?"
|
|
commands.execute(nquery, param={"nid" : existing_notification["id"]})
|
|
else:
|
|
# create un-assignment notification
|
|
nquery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 5, ?message?)"
|
|
commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : elem["participant_id"], "message" : message})
|
|
break
|
|
|
|
if schemaModel["canceled"] is not None:
|
|
if schemaModel["canceled"] and not was_canceled:
|
|
# create a canceled notification for all currently assigned participants
|
|
stornoNotificationQuery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 7, ?message?)"
|
|
for participant_assignment in schemaModel["participants"]:
|
|
commands.execute(stornoNotificationQuery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "message" : message})
|
|
|
|
# save history data
|
|
# TODO: set ETA properly
|
|
# query = SQLQuery.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)"
|
|
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)
|
|
|
|
except Exception as ex:
|
|
logging.error(traceback.format_exc())
|
|
logging.error(ex)
|
|
print(ex)
|
|
result = {}
|
|
result["error_field"] = "call failed"
|
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
|
|
|
finally:
|
|
if pooledConnection is not None:
|
|
pooledConnection.close()
|
|
|