from __future__ import annotations
from onegov.core.orm.abstract import AdjacencyList
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.mixins import TimestampMixin
from onegov.gazette.observer import observes
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import or_
from sqlalchemy.orm import object_session
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Iterator
from collections.abc import Sequence
from onegov.gazette.models.notice import GazetteNotice
from sqlalchemy.orm import Query
from sqlalchemy.orm import relationship
[docs]
class Category(AdjacencyList, ContentMixin, TimestampMixin):
""" Defines a category for official notices.
Although the categories are defined as an adjacency list, we currently
use it only as a simple alphabetically ordered key-value list (name-title).
"""
[docs]
__tablename__ = 'gazette_categories'
#: True, if this category is still in use.
[docs]
active: Column[bool | None] = Column(Boolean, nullable=True)
if TYPE_CHECKING:
# we need to override these attributes to get the correct base class
[docs]
parent: relationship[Category | None]
children: relationship[Sequence[Category]]
@property
def root(self) -> Category: ...
@property
def ancestors(self) -> Iterator[Category]: ...
[docs]
def notices(self) -> Query[GazetteNotice]:
""" Returns a query to get all notices related to this category. """
from onegov.gazette.models.notice import GazetteNotice # circular
notices = object_session(self).query(GazetteNotice)
notices = notices.filter(
GazetteNotice._categories.has_key(self.name) # type:ignore
)
return notices
@property
[docs]
def in_use(self) -> bool:
""" True, if the category is used by any notice. """
if self.notices().first():
return True
return False
@observes('title')
[docs]
def title_observer(self, title: str) -> None:
""" Changes the category title of the notices when updating the title
of the category.
"""
from onegov.gazette.models.notice import GazetteNotice # circular
notices = self.notices()
notices = notices.filter(
or_(
GazetteNotice.category.is_(None),
GazetteNotice.category != title
)
)
for notice in notices:
notice.category = title