Source code for org.models.meeting

from __future__ import annotations

from datetime import datetime
from functools import cached_property
from markupsafe import Markup
from onegov.core.collection import GenericCollection
from onegov.core.orm import Base
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.mixins import dict_property, content_property
from onegov.file import MultiAssociatedFiles
from onegov.org import _
from onegov.org.models.extensions import AccessExtension
from onegov.org.models.extensions import GeneralFileLinkExtension
from onegov.search import ORMSearchable
from sedate import utcnow
from sqlalchemy import func
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import mapped_column, relationship, Mapped
from uuid import uuid4, UUID

from typing import TYPE_CHECKING, Self
if TYPE_CHECKING:
    from onegov.org.models import MeetingItem
    from sqlalchemy.orm import Query
    from sqlalchemy.orm import Session


[docs] class Meeting( AccessExtension, MultiAssociatedFiles, Base, ContentMixin, GeneralFileLinkExtension, ORMSearchable, ):
[docs] __tablename__ = 'par_meetings'
[docs] fts_type_title = _('Meetings')
[docs] fts_public = True
[docs] fts_title_property = 'display_name'
[docs] fts_properties = { 'title_text': {'type': 'text', 'weight': 'A'}, 'display_name': {'type': 'text', 'weight': 'A'} }
@property
[docs] def fts_suggestion(self) -> list[str]: return [self.title_text, self.display_name]
@property
[docs] def fts_last_change(self) -> datetime | None: # NOTE: More current meetings should be more relevant # FIXME: Should we de-prioritize meetings without a date # or maybe even exclude them from search results? # Currently they would be as relevant as current # meetings. return self.start_datetime
@property
[docs] def title_text(self) -> str: if self.start_datetime is not None: return f'{self.title} ({self.start_datetime})' return self.title
@property
[docs] def display_name(self) -> str: # return title and start_datetime as dmY if self.start_datetime is not None: return f'{self.title} {self.start_datetime:%d.%m.%Y}' return self.title
#: Internal ID
[docs] id: Mapped[UUID] = mapped_column( primary_key=True, default=uuid4, )
#: The title of the meeting
[docs] title: Mapped[str]
#: date and time of the meeting start
[docs] start_datetime: Mapped[datetime | None]
#: date and time of the meeting end
[docs] end_datetime: Mapped[datetime | None]
#: location address of meeting
[docs] address: Mapped[Markup]
[docs] description: Mapped[Markup | None]
#: The meeting items
[docs] meeting_items: Mapped[list[MeetingItem]] = ( relationship( 'MeetingItem', cascade='all, delete-orphan', back_populates='meeting', order_by='desc(MeetingItem.number)' ) )
#: link to audio url #: link to video url @hybrid_property
[docs] def past(self): return self.start_datetime < utcnow() if self.start_datetime else False
@past.expression # type:ignore[no-redef] def past(cls): return cls.start_datetime < func.now()
[docs] def __repr__(self) -> str: return f'<Meeting {self.title}, {self.start_datetime}>'
[docs] class MeetingCollection(GenericCollection[Meeting]): def __init__( self, session: Session, past: bool | None = None ) -> None: super().__init__(session)
[docs] self.past = past
@cached_property
[docs] def title(self) -> str: return _('Meeting')
@property
[docs] def model_class(self) -> type[Meeting]: return Meeting
[docs] def query(self) -> Query[Meeting]: query = super().query() Meeting = self.model_class # noqa: N806 if self.past is not None: if self.past: query = query.filter(Meeting.start_datetime < utcnow()) query = query.order_by(Meeting.start_datetime.desc()) else: query = query.filter(Meeting.start_datetime >= utcnow()) query = query.order_by(Meeting.start_datetime.asc()) return query
[docs] def for_filter(self, past: bool | None = None) -> Self: return self.__class__(self.session, past=past)