from onegov.core.orm import Base
from onegov.core.orm.abstract import associated
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.types import UUID, UTCDateTime
from onegov.file import File
from onegov.org.models import AccessExtension
from sedate import to_timezone
from sqlalchemy import (
Boolean, Column, ForeignKey, Integer, Numeric, Text, Enum
)
from sqlalchemy.orm import relationship
from uuid import uuid4
from typing import Literal, TYPE_CHECKING
if TYPE_CHECKING:
import uuid
from datetime import datetime
from decimal import Decimal
from typing import 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: 'Column[uuid.UUID]' = Column(
UUID, # type:ignore[arg-type]
primary_key=True,
default=uuid4
)
#: the date of the report
[docs]
date: 'Column[datetime]' = Column(UTCDateTime, nullable=False)
#: how long the mission lasted, in hours
[docs]
duration: 'Column[Decimal]' = Column(
Numeric(precision=6, scale=2),
nullable=False
)
#: the nature of the mission
[docs]
nature: 'Column[str]' = Column(Text, nullable=False)
#: the location of the mission
[docs]
location: 'Column[str]' = Column(Text, nullable=False)
#: actually active personnel
[docs]
personnel: 'Column[int]' = Column(Integer, nullable=False)
#: backup personnel
[docs]
backup: 'Column[int]' = Column(Integer, nullable=False)
#: the Zivilschutz was involved
[docs]
civil_defence: 'Column[bool]' = Column(
Boolean,
nullable=False,
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: 'Column[int]' = Column(Integer, nullable=False, default=1)
# the mission type
[docs]
mission_type: 'Column[MissionType]' = Column(
Enum(*MISSION_TYPES, name='mission_type'), # type:ignore[arg-type]
nullable=False,
default='single'
)
[docs]
used_vehicles: 'relationship[list[MissionReportVehicleUse]]'
used_vehicles = relationship(
'MissionReportVehicleUse',
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: 'Column[uuid.UUID]' = Column(
UUID, # type:ignore[arg-type]
primary_key=True,
default=uuid4
)
#: the short id of the vehicle
[docs]
name: 'Column[str]' = Column(Text, nullable=False)
#: the longer name of the vehicle
[docs]
description: 'Column[str]' = Column(Text, nullable=False)
#: symbol of the vehicle
[docs]
symbol = associated(MissionReportFile, 'symbol', 'one-to-one')
#: a website describing the vehicle
[docs]
website: 'Column[str | None]' = Column(Text, nullable=True)
[docs]
uses: 'relationship[list[MissionReportVehicleUse]]' = relationship(
'MissionReportVehicleUse',
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: 'Column[uuid.UUID]' = Column(
UUID, # type:ignore[arg-type]
ForeignKey('mission_reports.id'),
primary_key=True
)
[docs]
mission_report: 'relationship[MissionReport]' = relationship(
MissionReport,
back_populates='used_vehicles'
)
[docs]
vehicle_id: 'Column[uuid.UUID]' = Column(
UUID, # type:ignore[arg-type]
ForeignKey('mission_report_vehicles.id'),
primary_key=True
)
[docs]
vehicle: 'relationship[MissionReportVehicle]' = relationship(
MissionReportVehicle,
back_populates='uses'
)
# vehicles may be used multiple times in a single mission_report
[docs]
count = Column(
Integer,
nullable=False,
default=1
)