Source code for election_day.models.screen

from collections import OrderedDict
from onegov.election_day.models.election import Election
from onegov.election_day.models.election_compound import ElectionCompound
from onegov.election_day.models.election_compound import ElectionCompoundPart
from onegov.election_day.models.vote import Vote
from onegov.core.orm import Base
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.mixins import TimestampMixin
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Text
from sqlalchemy.orm import object_session
from sqlalchemy.orm import relationship


from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from datetime import datetime


[docs] class ScreenType:
[docs] types = ( 'simple_vote', 'complex_vote', 'majorz_election', 'proporz_election', 'election_compound', 'election_compound_part' )
def __init__(self, type_: str): assert type_ in self.types
[docs] self.type = type_
@property
[docs] def categories(self) -> tuple[str, ...]: if self.type == 'simple_vote': return ('generic', 'vote') if self.type == 'complex_vote': return ('generic', 'vote', 'complex_vote') if self.type == 'majorz_election': return ('generic', 'election', 'majorz_election') if self.type == 'proporz_election': return ('generic', 'election', 'proporz_election') if self.type == 'election_compound': return ('generic', 'election_compound') if self.type == 'election_compound_part': return ('generic', 'election_compound') raise NotImplementedError()
[docs] class Screen(Base, ContentMixin, TimestampMixin):
[docs] __tablename__ = 'election_day_screens'
#: Identifies the screen
[docs] id: 'Column[int]' = Column(Integer, primary_key=True)
#: A unique number for the path
[docs] number: 'Column[int]' = Column(Integer, unique=True, nullable=False)
#: The vote
[docs] vote_id: 'Column[str | None]' = Column( Text, ForeignKey(Vote.id, onupdate='CASCADE'), nullable=True )
[docs] vote: 'relationship[Vote | None]' = relationship( 'Vote', back_populates='screens' )
#: The election
[docs] election_id: 'Column[str | None]' = Column( Text, ForeignKey(Election.id, onupdate='CASCADE'), nullable=True )
[docs] election: 'relationship[Election | None]' = relationship( 'Election', back_populates='screens' )
#: The election compound
[docs] election_compound_id: 'Column[str | None]' = Column( Text, ForeignKey(ElectionCompound.id, onupdate='CASCADE'), nullable=True )
[docs] election_compound: 'relationship[ElectionCompound | None]' = relationship( 'ElectionCompound', back_populates='screens' )
#: The domain of the election compound part.
[docs] domain: 'Column[str | None]' = Column(Text, nullable=True)
#: The domain segment of the election compound part.
[docs] domain_segment: 'Column[str | None]' = Column(Text, nullable=True)
@property
[docs] def election_compound_part(self) -> ElectionCompoundPart | None: if self.election_compound and self.domain and self.domain_segment: return ElectionCompoundPart( self.election_compound, self.domain, self.domain_segment ) return None
#: The title
[docs] description: 'Column[str | None]' = Column(Text, nullable=True)
#: The type
[docs] type: 'Column[str]' = Column(Text, nullable=False)
#: The content of the screen
[docs] structure: 'Column[str]' = Column(Text, nullable=False)
#: Additional CSS
[docs] css: 'Column[str | None]' = Column(Text, nullable=True)
#: The group this screen belongs to, used for cycling
[docs] group: 'Column[str | None]' = Column(Text, nullable=True)
#: The duration this screen is presented if cycling
[docs] duration: 'Column[int | None]' = Column(Integer, nullable=True)
@property
[docs] def model( self ) -> Election | ElectionCompound | ElectionCompoundPart | Vote | None: if self.type in ('simple_vote', 'complex_vote'): return self.vote if self.type in ('majorz_election', 'proporz_election'): return self.election if self.type == 'election_compound': return self.election_compound if self.type == 'election_compound_part': return self.election_compound_part raise NotImplementedError()
@property
[docs] def screen_type(self) -> ScreenType: return ScreenType(self.type)
@property
[docs] def last_modified(self) -> 'datetime | None': model = self.model assert model is not None changes = [self.last_change, model.last_change] set_changes = [change for change in changes if change] return max(set_changes) if set_changes else None
@property
[docs] def next(self) -> 'Screen | None': if self.group: session = object_session(self) query = session.query(Screen.number, Screen) query = query.filter_by(group=self.group).order_by(Screen.number) screens = OrderedDict(query.all()) if len(screens) > 1: keys = tuple(screens.keys()) index = (keys.index(self.number) + 1) % len(screens) return screens[keys[index]] return None