Skip to content
Snippets Groups Projects
models.py 5.65 KiB
import logging

from django.db import models
from django.utils import timezone
from wagtail.admin.edit_handlers import (
    FieldPanel,
    MultiFieldPanel,
    PublishingPanel,
    StreamFieldPanel,
)
from wagtail.core.fields import StreamField
from wagtail.core.models import Page
from wagtail.images.edit_handlers import ImageChooserPanel

from shared.blocks import DEFAULT_CONTENT_BLOCKS, MenuItemBlock, MenuParentBlock

logger = logging.getLogger(__name__)


class SubpageMixin:
    """Must be used in class definition before MetadataPageMixin!"""

    @property
    def root_page(self):
        if not hasattr(self, "_root_page"):
            # vypada to hackove ale lze takto pouzit: dle dokumentace get_ancestors
            # vraci stranky v poradi od rootu, tedy domovska stranka je druha v poradi
            self._root_page = self.get_ancestors().specific()[1]
        return self._root_page

    def get_meta_image(self):
        return self.search_image or self.root_page.get_meta_image()


class ArticleMixin(models.Model):
    """
    Common fields for articles.

    Must be used in class definition before MetadataPageMixin!

    If you want to tag articles, add tags as `tags` field in article page model.
    """

    ### FIELDS

    content = StreamField(
        DEFAULT_CONTENT_BLOCKS,
        verbose_name="Článek",
        blank=True,
    )
    date = models.DateField("datum", default=timezone.now)
    perex = models.TextField("perex")
    author = models.CharField("autor", max_length=250, blank=True, null=True)
    image = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="obrázek",
    )

    ### PANELS

    content_panels = Page.content_panels + [
        FieldPanel("date"),
        FieldPanel("perex"),
        StreamFieldPanel("content"),
        FieldPanel("author"),
        ImageChooserPanel("image"),
    ]

    settings_panels = [PublishingPanel()]

    class Meta:
        abstract = True

    @classmethod
    def has_tags(cls):
        try:
            cls._meta.get_field("tags")
        except models.FieldDoesNotExist:
            return False
        return True

    def tag_filter_page(self):
        """Page used for filtering by tags in url like `?tag=foo`."""
        return self.get_parent()

    def get_meta_image(self):
        if hasattr(self, "search_image") and self.search_image:
            return self.search_image
        return self.image

    def get_meta_description(self):
        if hasattr(self, "search_description") and self.search_description:
            return self.search_description
        return self.perex


class MenuMixin(Page):
    menu = StreamField(
        [("menu_item", MenuItemBlock()), ("menu_parent", MenuParentBlock())],
        verbose_name="Menu",
        blank=True,
    )

    menu_panels = [
        MultiFieldPanel(
            [
                StreamFieldPanel("menu"),
            ],
            heading="Menu Options",
        ),
    ]

    class Meta:
        abstract = True


class ExtendedMetadataHomePageMixin(models.Model):
    """Use for site home page to define metadata title suffix.

    Must be used in class definition before MetadataPageMixin!
    """

    title_suffix = models.CharField(
        "Přípona titulku stránky",
        max_length=100,
        blank=True,
        null=True,
        help_text="Umožňuje přidat příponu k základnímu titulku stránky. Pokud "
        "je např. titulek stránky pojmenovaný 'Kontakt' a do přípony vyplníte "
        "'MS Pardubice | Piráti', výsledný titulek bude "
        "'Kontakt | MS Pardubice | Piráti'. Pokud příponu nevyplníte, použije "
        "se název webu.",
    )

    class Meta:
        abstract = True

    def get_meta_title_suffix(self):
        if self.title_suffix:
            return self.title_suffix

        if hasattr(super(), "get_meta_title"):
            return super().get_meta_title()

        return self.get_site().site_name

    def get_meta_title(self):
        title = super().get_meta_title()
        suffix = self.get_meta_title_suffix()

        # Covers scenario when title_suffix is not set and evaluates to super().get_meta_title() value.
        # Rather than having MS Pardubice | MS Pardubice, just use MS Pardubice alone.
        if title != suffix:
            return f"{super().get_meta_title()} | {self.get_meta_title_suffix()}"

        return title


class ExtendedMetadataPageMixin(models.Model):
    """Use for pages except for home page to use shared metadata title suffix.

    There are few rules on how to use this:

    - Do not forget to list ExtendedMetadataHomePageMixin among ancestors of the related HomePage class.
    - Must be used in class definition before MetadataPageMixin.
    - Expects SubpageMixin or equivalent exposing `root_page` property to be used for the page too.
    """

    class Meta:
        abstract = True

    def get_meta_title_suffix(self):
        if not hasattr(self, "root_page"):
            logger.warning(
                "Using `ExtendedMetadataPageMixin` without `SubpageMixin` for %s",
                repr(self),
            )
            return None

        if not hasattr(self.root_page, "get_meta_title_suffix"):
            logger.warning(
                "Using `ExtendedMetadataPageMixin` without `ExtendedMetadataHomePageMixin` on the root page for %s",
                repr(self),
            )
            return None

        return self.root_page.get_meta_title_suffix()

    def get_meta_title(self):
        suffix = self.get_meta_title_suffix()

        if not suffix:
            return super().get_meta_title()

        return f"{super().get_meta_title()} | {self.get_meta_title_suffix()}"