Source code for directory.models.directory_entry

from onegov.core.orm import Base
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.mixins import TimestampMixin
from onegov.core.orm.mixins import UTCPublicationMixin
from onegov.core.orm.types import UUID
from onegov.file import AssociatedFiles
from onegov.gis import CoordinatesMixin
from onegov.search import SearchableContent
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Index
from sqlalchemy import Text
from sqlalchemy.dialects.postgresql import HSTORE
from sqlalchemy.ext.mutable import MutableDict
from sqlalchemy.orm import relationship
from uuid import uuid4


from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
    import uuid
    from collections.abc import Collection
    from .directory import Directory


[docs] class DirectoryEntry(Base, ContentMixin, CoordinatesMixin, TimestampMixin, SearchableContent, AssociatedFiles, UTCPublicationMixin): """ A single entry of a directory. """
[docs] __tablename__ = 'directory_entries'
[docs] es_properties = { 'keywords': {'type': 'keyword'}, 'title': {'type': 'localized'}, 'lead': {'type': 'localized'}, 'directory_id': {'type': 'keyword'}, # since the searchable text might include html, we remove it # even if there's no html -> possibly decreasing the search # quality a bit 'text': {'type': 'localized_html'} }
@property
[docs] def es_public(self) -> bool: return False # to be overridden downstream
#: An interal id for references (not public)
[docs] id: 'Column[uuid.UUID]' = Column( UUID, # type:ignore[arg-type] primary_key=True, default=uuid4 )
#: The public id of the directory entry
[docs] name: 'Column[str]' = Column(Text, nullable=False)
#: The directory this entry belongs to
[docs] directory_id: 'Column[UUID]' = Column( ForeignKey('directories.id'), nullable=False)
#: the polymorphic type of the entry
[docs] type: 'Column[str]' = Column( Text, nullable=False, default=lambda: 'generic' )
#: The order of the entry in the directory
[docs] order: 'Column[str]' = Column(Text, nullable=False, index=True)
#: The title of the entry
[docs] title: 'Column[str]' = Column(Text, nullable=False)
#: Describes the entry briefly
[docs] lead: 'Column[str | None]' = Column(Text, nullable=True)
#: All keywords defined for this entry (indexed)
[docs] _keywords: 'Column[dict[str, str] | None]' = Column( # type:ignore MutableDict.as_mutable(HSTORE), nullable=True, name='keywords' )
[docs] __mapper_args__ = { 'polymorphic_on': type, 'polymorphic_identity': 'generic', }
[docs] __table_args__ = ( Index('inverted_keywords', 'keywords', postgresql_using='gin'), Index('unique_entry_name', 'directory_id', 'name', unique=True), )
[docs] directory: 'relationship[Directory]' = relationship( 'Directory', back_populates='entries' )
@property @property @property @property
[docs] def directory_name(self) -> str: return self.directory.name
@property
[docs] def keywords(self) -> set[str]: return set(self._keywords.keys()) if self._keywords else set()
# FIXME: asymmetric properties are not supported by mypy, switch to # a custom descriptor, if desired. @keywords.setter def keywords(self, value: 'Collection[str] | None') -> None: self._keywords = dict.fromkeys(value, '') if value else None @property
[docs] def text(self) -> str: return self.directory.configuration.extract_searchable(self.values)
@property
[docs] def values(self) -> dict[str, Any]: return self.content.get('values', {}) if self.content else {}
@values.setter def values(self, values: dict[str, Any]) -> None: self.content = self.content or {} self.content['values'] = values self.content.changed() # type:ignore[attr-defined]