diff --git a/src/server/BreCal/impl/login.py b/src/server/BreCal/impl/login.py index bfc16cd..668dac7 100644 --- a/src/server/BreCal/impl/login.py +++ b/src/server/BreCal/impl/login.py @@ -35,10 +35,10 @@ def GetUser(options): "user_name": data[0].user_name, "user_phone": data[0].user_phone, "user_email": data[0].user_email, - "notify_email": data[0].notify_email, - "notify_whatsapp": data[0].notify_whatsapp, - "notify_signal": data[0].notify_signal, - "notify_popup": data[0].notify_popup, + "notify_email": model._coerce_bool(data[0].notify_email), + "notify_whatsapp": model._coerce_bool(data[0].notify_whatsapp), + "notify_signal": model._coerce_bool(data[0].notify_signal), + "notify_popup": model._coerce_bool(data[0].notify_popup), "notify_on": model.notification_types_to_names(model.bitflag_to_list(data[0].notify_event)) } token = jwt_handler.generate_jwt(payload=result, lifetime=120) # generate token valid 60 mins diff --git a/src/server/BreCal/schemas/model.py b/src/server/BreCal/schemas/model.py index dc99e61..f371950 100644 --- a/src/server/BreCal/schemas/model.py +++ b/src/server/BreCal/schemas/model.py @@ -24,6 +24,15 @@ def obj_dict(obj): return obj.to_json() return obj.__dict__ +def _coerce_bool(value): + if value is None: + return None + if isinstance(value, bool): + return value + if isinstance(value, int) and value in (0, 1): + return bool(value) + return value + @dataclass class Berth(Schema): id: int @@ -36,6 +45,19 @@ class Berth(Schema): modified: datetime deleted: bool + def to_json(self): + return { + "id": self.id, + "name": self.name, + "lock": _coerce_bool(self.lock), + "owner_id": self.owner_id, + "authority_id": self.authority_id, + "port_id": self.port_id, + "created": self.created.isoformat() if self.created else "", + "modified": self.modified.isoformat() if self.modified else "", + "deleted": _coerce_bool(self.deleted), + } + @dataclass class Port(Schema): id: int @@ -45,6 +67,16 @@ class Port(Schema): modified: datetime deleted: bool + def to_json(self): + return { + "id": self.id, + "name": self.name, + "locode": self.locode, + "created": self.created.isoformat() if self.created else "", + "modified": self.modified.isoformat() if self.modified else "", + "deleted": _coerce_bool(self.deleted), + } + class OperationType(IntEnum): undefined = 0 insert = 1 @@ -212,6 +244,21 @@ class Participant(Schema): deleted: bool ports: List[int] = field(default_factory=list) + def to_json(self): + return { + "id": self.id, + "name": self.name, + "street": self.street, + "postal_code": self.postal_code, + "city": self.city, + "type": self.type, + "flags": self.flags, + "created": self.created.isoformat() if self.created else "", + "modified": self.modified.isoformat() if self.modified else "", + "deleted": _coerce_bool(self.deleted), + "ports": self.ports, + } + @validates("type") def validate_type(self, value, **kwargs): # e.g., when an IntFlag has the values 1,2,4; the maximum valid value is 7 @@ -370,25 +417,25 @@ class Shipcall: "etd": self.etd.isoformat() if self.etd else "", "arrival_berth_id": self.arrival_berth_id, "departure_berth_id": self.departure_berth_id, - "tug_required": self.tug_required, - "pilot_required": self.pilot_required, + "tug_required": _coerce_bool(self.tug_required), + "pilot_required": _coerce_bool(self.pilot_required), "flags": self.flags, - "pier_side": self.pier_side, - "bunkering": self.bunkering, - "replenishing_terminal": self.replenishing_terminal, - "replenishing_lock": self.replenishing_lock, + "pier_side": _coerce_bool(self.pier_side), + "bunkering": _coerce_bool(self.bunkering), + "replenishing_terminal": _coerce_bool(self.replenishing_terminal), + "replenishing_lock": _coerce_bool(self.replenishing_lock), "draft": self.draft, "tidal_window_from": self.tidal_window_from.isoformat() if self.tidal_window_from else "", "tidal_window_to": self.tidal_window_to.isoformat() if self.tidal_window_to else "", - "rain_sensitive_cargo": self.rain_sensitive_cargo, + "rain_sensitive_cargo": _coerce_bool(self.rain_sensitive_cargo), "recommended_tugs": self.recommended_tugs, - "anchored": self.anchored, - "moored_lock": self.moored_lock, - "canceled": self.canceled, + "anchored": _coerce_bool(self.anchored), + "moored_lock": _coerce_bool(self.moored_lock), + "canceled": _coerce_bool(self.canceled), "evaluation": self.evaluation.name if isinstance(self.evaluation, IntEnum) else EvaluationType(self.evaluation).name, "evaluation_message": self.evaluation_message, "evaluation_time": self.evaluation_time.isoformat() if self.evaluation_time else "", - "evaluation_notifications_sent": self.evaluation_notifications_sent, + "evaluation_notifications_sent": _coerce_bool(self.evaluation_notifications_sent), "time_ref_point": self.time_ref_point, "port_id": self.port_id, "created": self.created.isoformat() if self.created else "", @@ -400,7 +447,39 @@ class Shipcall: @classmethod def from_query_row(self, id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, evaluation_message, evaluation_time, evaluation_notifications_sent, time_ref_point, port_id, created, modified): - return self(id, ship_id, ShipcallType(type), eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, EvaluationType(evaluation), evaluation_message, evaluation_time, evaluation_notifications_sent, time_ref_point, port_id, created, modified) + return self( + id, + ship_id, + ShipcallType(type), + eta, + voyage, + etd, + arrival_berth_id, + departure_berth_id, + _coerce_bool(tug_required), + _coerce_bool(pilot_required), + flags, + _coerce_bool(pier_side), + _coerce_bool(bunkering), + _coerce_bool(replenishing_terminal), + _coerce_bool(replenishing_lock), + draft, + tidal_window_from, + tidal_window_to, + _coerce_bool(rain_sensitive_cargo), + recommended_tugs, + _coerce_bool(anchored), + _coerce_bool(moored_lock), + _coerce_bool(canceled), + EvaluationType(evaluation), + evaluation_message, + evaluation_time, + _coerce_bool(evaluation_notifications_sent), + time_ref_point, + port_id, + created, + modified + ) class ShipcallId(Schema): pass @@ -567,6 +646,34 @@ class Times: created: datetime modified: datetime + def to_json(self): + return { + "id": self.id, + "eta_berth": self.eta_berth.isoformat() if self.eta_berth else "", + "eta_berth_fixed": _coerce_bool(self.eta_berth_fixed), + "etd_berth": self.etd_berth.isoformat() if self.etd_berth else "", + "etd_berth_fixed": _coerce_bool(self.etd_berth_fixed), + "lock_time": self.lock_time.isoformat() if self.lock_time else "", + "lock_time_fixed": _coerce_bool(self.lock_time_fixed), + "zone_entry": self.zone_entry.isoformat() if self.zone_entry else "", + "zone_entry_fixed": _coerce_bool(self.zone_entry_fixed), + "operations_start": self.operations_start.isoformat() if self.operations_start else "", + "operations_end": self.operations_end.isoformat() if self.operations_end else "", + "remarks": self.remarks, + "participant_id": self.participant_id, + "berth_id": self.berth_id, + "berth_info": self.berth_info, + "pier_side": _coerce_bool(self.pier_side), + "participant_type": self.participant_type, + "shipcall_id": self.shipcall_id, + "ata": self.ata.isoformat() if self.ata else "", + "atd": self.atd.isoformat() if self.atd else "", + "eta_interval_end": self.eta_interval_end.isoformat() if self.eta_interval_end else "", + "etd_interval_end": self.etd_interval_end.isoformat() if self.etd_interval_end else "", + "created": self.created.isoformat() if self.created else "", + "modified": self.modified.isoformat() if self.modified else "", + } + @dataclass class User: @@ -610,6 +717,23 @@ class Ship: modified: datetime deleted: bool + def to_json(self): + return { + "id": self.id, + "name": self.name, + "imo": self.imo, + "callsign": self.callsign, + "participant_id": self.participant_id, + "length": self.length, + "width": self.width, + "is_tug": _coerce_bool(self.is_tug), + "bollard_pull": self.bollard_pull, + "eni": self.eni, + "created": self.created.isoformat() if self.created else "", + "modified": self.modified.isoformat() if self.modified else "", + "deleted": _coerce_bool(self.deleted), + } + class ShipSchema(Schema): def __init__(self):