Source code for betty.ancestry.citation

"""
Data types for citations.
"""

from __future__ import annotations

from typing import final, Iterable, TYPE_CHECKING
from urllib.parse import quote

from typing_extensions import override

from betty.ancestry.date import HasDate
from betty.ancestry.has_file_references import HasFileReferences
from betty.ancestry.link import HasLinks
from betty.ancestry.privacy import HasPrivacy, Privacy, merge_privacies
from betty.ancestry.source import Source
from betty.json.schema import Object, Array, String
from betty.locale.localizable import (
    _,
    OptionalStaticTranslationsLocalizableAttr,
    ShorthandStaticTranslations,
    Localizable,
)
from betty.model import (
    UserFacingEntity,
    Entity,
    GeneratedEntityId,
    EntityReferenceSchema,
)
from betty.model.association import ManyToMany, ManyToOne
from betty.plugin import ShorthandPluginBase

if TYPE_CHECKING:
    from betty.ancestry.has_citations import HasCitations  # noqa F401
    from betty.serde.dump import DumpMapping, Dump
    from betty.project import Project
    from betty.date import Datey
    from betty.ancestry.file_reference import FileReference


[docs] @final class Citation( ShorthandPluginBase, HasDate, HasFileReferences, HasPrivacy, HasLinks, UserFacingEntity, ): """ A citation (a reference to a source). """ _plugin_id = "citation" _plugin_label = _("Citation") facts = ManyToMany["Citation", "HasCitations"]( "betty.ancestry.citation:Citation", "facts", "betty.ancestry.has_citations:HasCitations", "citations", ) source = ManyToOne["Citation", Source]( "betty.ancestry.citation:Citation", "source", "betty.ancestry.source:Source", "citations", ) #: The human-readable citation location. location = OptionalStaticTranslationsLocalizableAttr("location")
[docs] def __init__( self, *, id: str | None = None, # noqa A002 # noqa A002 facts: Iterable["HasCitations & Entity"] | None = None, source: Source | None = None, location: ShorthandStaticTranslations | None = None, date: Datey | None = None, file_references: Iterable[FileReference] | None = None, privacy: Privacy | None = None, public: bool | None = None, private: bool | None = None, ): super().__init__( id, date=date, file_references=file_references, privacy=privacy, public=public, private=private, ) if facts is not None: self.facts = facts if location: self.location = location self.source = source
@override def _get_effective_privacy(self) -> Privacy: privacy = super()._get_effective_privacy() if self.source: return merge_privacies(privacy, self.source.privacy) return privacy
[docs] @override @classmethod def plugin_label_plural(cls) -> Localizable: return _("Citations")
@override @property def label(self) -> Localizable: return self.location or super().label
[docs] @override async def dump_linked_data(self, project: Project) -> DumpMapping[Dump]: dump = await super().dump_linked_data(project) dump["@type"] = "https://schema.org/Thing" dump["facts"] = [ project.static_url_generator.generate( f"/{fact.plugin_id()}/{quote(fact.id)}/index.json" ) for fact in self.facts if not isinstance(fact.id, GeneratedEntityId) ] if self.source is not None and not isinstance( self.source.id, GeneratedEntityId ): dump["source"] = project.static_url_generator.generate( f"/source/{quote(self.source.id)}/index.json" ) return dump
[docs] @override @classmethod async def linked_data_schema(cls, project: Project) -> Object: schema = await super().linked_data_schema(project) schema.add_property( "source", EntityReferenceSchema(Source, title="Source"), False ) schema.add_property( "facts", Array( String( format=String.Format.URI, title="Fact", description="A reference to a JSON resource that is a fact referencing this citation.", ), title="Facts", ), ) return schema