from __future__ import annotations
from datetime import datetime
from decimal import Decimal
from onegov.core.orm import Base
from onegov.core.orm.abstract import associated
from onegov.core.orm.mixins import ContentMixin
from onegov.file import File
from onegov.org.models import AccessExtension
from sedate import to_timezone
from sqlalchemy import Enum, ForeignKey, Numeric
from sqlalchemy.orm import mapped_column, relationship, Mapped
from uuid import uuid4, UUID
from typing import Literal, TypeAlias
[docs]
MissionType: TypeAlias = Literal['single', 'multi']
[docs]
MISSION_TYPES: tuple[MissionType, ...] = ('single', 'multi')
[docs]
class MissionReportFile(File):
[docs]
__mapper_args__ = {'polymorphic_identity': 'mission-report-file'}
[docs]
class MissionReport(Base, ContentMixin, AccessExtension):
[docs]
__tablename__ = 'mission_reports'
#: the public id of the mission_report
[docs]
id: Mapped[UUID] = mapped_column(
primary_key=True,
default=uuid4
)
#: the date of the report
#: how long the mission lasted, in hours
[docs]
duration: Mapped[Decimal] = mapped_column(
Numeric(precision=6, scale=2)
)
#: the nature of the mission
#: the location of the mission
#: actually active personnel
#: backup personnel
#: the Zivilschutz was involved
[docs]
civil_defence: Mapped[bool] = mapped_column(default=False)
#: pictures of the mission
[docs]
pictures = associated(MissionReportFile, 'pictures', 'one-to-many')
# The number of missions on the same site during a day
[docs]
mission_count: Mapped[int] = mapped_column(default=1)
# the mission type
[docs]
mission_type: Mapped[MissionType] = mapped_column(
Enum(*MISSION_TYPES, name='mission_type'),
default='single'
)
[docs]
used_vehicles: Mapped[list[MissionReportVehicleUse]] = relationship(
cascade='all, delete-orphan',
back_populates='mission_report'
)
@property
[docs]
def title(self) -> str:
return self.nature
@property
[docs]
def readable_duration(self) -> str:
return str(self.duration).rstrip('.0') + 'h'
@property
[docs]
def local_date(self) -> datetime:
return to_timezone(self.date, 'Europe/Zurich')
[docs]
class MissionReportVehicle(Base, ContentMixin, AccessExtension):
[docs]
__tablename__ = 'mission_report_vehicles'
#: the public id of the vehicle
[docs]
id: Mapped[UUID] = mapped_column(
primary_key=True,
default=uuid4
)
#: the short id of the vehicle
#: the longer name of the vehicle
[docs]
description: Mapped[str]
#: symbol of the vehicle
[docs]
symbol = associated(MissionReportFile, 'symbol', 'one-to-one')
#: a website describing the vehicle
[docs]
website: Mapped[str | None]
[docs]
uses: Mapped[list[MissionReportVehicleUse]] = relationship(
back_populates='vehicle'
)
@property
[docs]
def title(self) -> str:
return f'{self.name} - {self.description}'
@property
[docs]
def readable_website(self) -> str | None:
if self.website:
return (self.website.removeprefix('http://')
.removeprefix('https://'))
return None
[docs]
class MissionReportVehicleUse(Base):
""" Many to many association between vehicles and reports. """
[docs]
__tablename__ = 'mission_report_vehicle_usees'
[docs]
mission_report_id: Mapped[UUID] = mapped_column(
ForeignKey('mission_reports.id'),
primary_key=True
)
[docs]
mission_report: Mapped[MissionReport] = relationship(
back_populates='used_vehicles'
)
[docs]
vehicle_id: Mapped[UUID] = mapped_column(
ForeignKey('mission_report_vehicles.id'),
primary_key=True
)
[docs]
vehicle: Mapped[MissionReportVehicle] = relationship(
back_populates='uses'
)
# vehicles may be used multiple times in a single mission_report
[docs]
count: Mapped[int] = mapped_column(default=1)