Source code for winterthur.models.mission_report

from __future__ import annotations

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 )