-
jan.bednarik authoredjan.bednarik authored
models.py 14.43 KiB
from django import forms
from django.core.paginator import Paginator
from django.db import models
from django.utils.translation import gettext_lazy
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import TaggedItemBase
from wagtail.admin.edit_handlers import (
FieldPanel,
HelpPanel,
InlinePanel,
MultiFieldPanel,
ObjectList,
PublishingPanel,
StreamFieldPanel,
TabbedInterface,
)
from wagtail.contrib.forms.edit_handlers import FormSubmissionsPanel
from wagtail.contrib.forms.models import AbstractForm, AbstractFormField
from wagtail.contrib.table_block.blocks import TableBlock
from wagtail.core import blocks
from wagtail.core.fields import StreamField
from wagtail.core.models import Page
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtailmetadata.models import MetadataPageMixin
from shared.models import ArticleMixin, SubpageMixin
from tuning import help
from .constants import (
ALIGN_CHOICES,
ALIGN_CSS,
ARTICLES_PER_LINE,
ARTICLES_PER_PAGE,
BLACK_ON_WHITE,
COLOR_CHOICES,
COLOR_CSS,
LEFT,
RICH_TEXT_FEATURES,
)
class ColorBlock(blocks.StructBlock):
"""
Intended as parent class for blocks with color option.
"""
color = blocks.ChoiceBlock(COLOR_CHOICES, label="barva", default=BLACK_ON_WHITE)
def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context=parent_context)
if "css_class" not in context:
context["css_class"] = []
context["css_class"] += COLOR_CSS[value["color"]]
return context
class AlignBlock(blocks.StructBlock):
"""
Intended as parent class for blocks with align option.
"""
align = blocks.ChoiceBlock(
ALIGN_CHOICES, label="zarovnání", default=LEFT, widget=forms.RadioSelect
)
def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context=parent_context)
if "css_class" not in context:
context["css_class"] = []
context["css_class"] += ALIGN_CSS[value["align"]]
return context
class ColumnsTextBlock(blocks.StructBlock):
left_text = blocks.RichTextBlock(label="levý sloupec", features=RICH_TEXT_FEATURES)
right_text = blocks.RichTextBlock(
label="pravý sloupec", features=RICH_TEXT_FEATURES
)
class Meta:
label = "text dva sloupce"
icon = "doc-full"
group = "texty"
template = "uniweb/blocks/text_columns.html"
class AdvancedColumnsTextBlock(ColorBlock, AlignBlock):
left_text = blocks.RichTextBlock(label="levý sloupec", features=RICH_TEXT_FEATURES)
right_text = blocks.RichTextBlock(
label="pravý sloupec", features=RICH_TEXT_FEATURES
)
class Meta:
label = "text dva sloupce (pokročilý)"
icon = "doc-full"
group = "texty"
template = "uniweb/blocks/advanced_text_columns.html"
class AdvancedTitleBlock(ColorBlock, AlignBlock):
title = blocks.CharBlock(label="nadpis")
class Meta:
label = "nadpis (pokročilý)"
icon = "title"
group = "nadpisy"
template = "uniweb/blocks/advanced_title.html"
class PictureTitleBlock(ColorBlock):
title = blocks.CharBlock(label="nadpis")
picture = ImageChooserBlock(
label="obrázek",
help_text="rozměr na výšku 75px nebo více (obrázek bude zmenšen na výšku 75px)",
)
class Meta:
label = "nadpis (s obrázkem)"
icon = "title"
group = "nadpisy"
template = "uniweb/blocks/picture_title.html"
class AdvancedTextBlock(ColorBlock, AlignBlock):
text = blocks.RichTextBlock(label="text", features=RICH_TEXT_FEATURES)
class Meta:
label = "text (pokročilý)"
icon = "doc-full"
group = "texty"
template = "uniweb/blocks/advanced_text.html"
class PictureListBlock(ColorBlock):
items = blocks.ListBlock(
blocks.RichTextBlock(label="odstavec", features=RICH_TEXT_FEATURES),
label="odstavce",
)
picture = ImageChooserBlock(
label="obrázek",
# TODO rozměry v helpu
help_text="rozměr 25x25px nebo více (obrázek bude zmenšen na 25x25px)",
)
class Meta:
label = "seznam z obrázkovými odrážkami"
icon = "list-ul"
group = "texty"
template = "uniweb/blocks/picture_list.html"
class ArticlesBlock(blocks.StructBlock):
page = blocks.PageChooserBlock(
label="sekce článků", page_type=["uniweb.UniwebArticlesIndexPage"]
)
lines = blocks.IntegerBlock(
label="počet řádků",
default=1,
help_text="zobrazí se tři články na řádek",
)
class Meta:
label = "články"
icon = "folder-open-1"
group = "ostatní"
template = "uniweb/blocks/articles.html"
def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context=parent_context)
count = value["lines"] * ARTICLES_PER_LINE
context["articles"] = (
value["page"]
.get_children()
.live()
.specific()
.order_by("-uniwebarticlepage__date")[:count]
)
return context
class MenuItemBlock(blocks.StructBlock):
name = blocks.CharBlock(label="název")
page = blocks.PageChooserBlock(
label="stránka",
page_type=[
"uniweb.UniwebHomePage",
"uniweb.UniwebFlexiblePage",
"uniweb.UniwebArticlesIndexPage",
"uniweb.UniwebFormPage",
],
)
class Meta:
label = "stránka"
CONTENT_STREAM_BLOCKS = [
(
"title",
blocks.CharBlock(
label="nadpis",
icon="title",
group="nadpisy",
template="uniweb/blocks/title.html",
),
),
("advanced_title", AdvancedTitleBlock()),
("picture_title", PictureTitleBlock()),
(
"text",
blocks.RichTextBlock(
label="text",
features=RICH_TEXT_FEATURES,
group="texty",
template="uniweb/blocks/text.html",
),
),
("advanced_text", AdvancedTextBlock()),
("text_columns", ColumnsTextBlock()),
("advanced_text_columns", AdvancedColumnsTextBlock()),
(
"gallery",
blocks.ListBlock(
ImageChooserBlock(label="obrázek"),
label="galerie",
icon="image",
group="ostatní",
template="uniweb/blocks/gallery.html",
),
),
("picture_list", PictureListBlock()),
(
"table",
TableBlock(
label="tabulka",
group="ostatní",
template="uniweb/blocks/table.html",
),
),
("articles", ArticlesBlock()),
]
class UniwebArticleTag(TaggedItemBase):
content_object = ParentalKey("uniweb.UniwebArticlePage", on_delete=models.CASCADE)
class UniwebHomePage(Page, MetadataPageMixin):
### FIELDS
content = StreamField(
CONTENT_STREAM_BLOCKS, verbose_name="obsah stránky", blank=True
)
# settings
matomo_id = models.IntegerField(
"Matomo ID pro sledování návštěvnosti", blank=True, null=True
)
top_menu = StreamField(
[("item", MenuItemBlock())],
verbose_name="horní menu",
blank=True,
)
narrow_layout = models.BooleanField(
"zúžený obsah stránky",
default=False,
help_text="užší stránka je vhodná pro lepší čitelnost textů",
)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("content"),
]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(help.build(help.IMPORTANT_TITLE)),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [
MultiFieldPanel(
[
FieldPanel("matomo_id"),
FieldPanel("narrow_layout"),
],
"nastavení webu",
)
]
menu_panels = [StreamFieldPanel("top_menu")]
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading=gettext_lazy("Content")),
ObjectList(promote_panels, heading=gettext_lazy("Promote")),
ObjectList(
settings_panels, heading=gettext_lazy("Settings"), classname="settings"
),
ObjectList(menu_panels, heading="Menu"),
]
)
### RELATIONS
subpage_types = [
"uniweb.UniwebFlexiblePage",
"uniweb.UniwebArticlesIndexPage",
"uniweb.UniwebFormPage",
]
### OTHERS
class Meta:
verbose_name = "Univerzální web"
@property
def root_page(self):
return self
class UniwebFlexiblePage(Page, SubpageMixin, MetadataPageMixin):
### FIELDS
content = StreamField(
CONTENT_STREAM_BLOCKS, verbose_name="obsah stránky", blank=True
)
### PANELS
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(help.build(help.NO_SEO_TITLE, help.NO_SEARCH_IMAGE)),
],
gettext_lazy("Common page configuration"),
),
]
content_panels = Page.content_panels + [
StreamFieldPanel("content"),
]
settings_panels = []
### RELATIONS
parent_page_types = [
"uniweb.UniwebHomePage",
"uniweb.UniwebFlexiblePage",
"uniweb.UniwebFormPage",
]
subpage_types = ["uniweb.UniwebFlexiblePage", "uniweb.UniwebFormPage"]
### OTHERS
class Meta:
verbose_name = "Flexibilní stránka"
class UniwebArticlesIndexPage(Page, SubpageMixin, MetadataPageMixin):
### FIELDS
### PANELS
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(help.build(help.NO_SEO_TITLE, help.NO_SEARCH_IMAGE)),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = []
### RELATIONS
parent_page_types = ["uniweb.UniwebHomePage"]
subpage_types = ["uniweb.UniwebArticlePage"]
### OTHERS
class Meta:
verbose_name = "Sekce článků"
def get_context(self, request):
context = super().get_context(request)
num = request.GET.get("page")
tag = request.GET.get("tag")
articles = (
self.get_children().live().specific().order_by("-uniwebarticlepage__date")
)
if tag is not None:
articles = articles.filter(uniwebarticlepage__tags__name=tag)
context["articles"] = Paginator(articles, ARTICLES_PER_PAGE).get_page(num)
context["tags"] = UniwebArticleTag.tags_for(UniwebArticlePage).filter(
uniwebarticlepage__in=articles
)
context["active_tag"] = tag
return context
class UniwebArticlePage(Page, ArticleMixin, SubpageMixin, MetadataPageMixin):
### FIELDS
tags = ClusterTaggableManager(through=UniwebArticleTag, blank=True)
### PANELS
content_panels = ArticleMixin.content_panels + [FieldPanel("tags")]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(help.build(help.NO_SEO_TITLE, help.NO_SEARCH_IMAGE)),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [PublishingPanel()]
### RELATIONS
parent_page_types = ["uniweb.UniwebArticlesIndexPage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Článek"
def get_context(self, request):
context = super().get_context(request)
context["related_articles"] = (
self.get_siblings(inclusive=False)
.live()
.specific()
.order_by("-uniwebarticlepage__date")[:3]
)
return context
class UniwebFormField(AbstractFormField):
page = ParentalKey(
"UniwebFormPage", on_delete=models.CASCADE, related_name="form_fields"
)
class UniwebFormPage(AbstractForm, SubpageMixin, MetadataPageMixin):
### FIELDS
content_before = StreamField(
CONTENT_STREAM_BLOCKS, verbose_name="obsah stránky před formulářem", blank=True
)
content_after = StreamField(
CONTENT_STREAM_BLOCKS, verbose_name="obsah stránky za formulářem", blank=True
)
content_landing = StreamField(
CONTENT_STREAM_BLOCKS,
verbose_name="obsah stránky zobrazené po odeslání formuláře",
blank=True,
)
### PANELS
content_panels = AbstractForm.content_panels + [
FormSubmissionsPanel(),
StreamFieldPanel("content_before"),
InlinePanel("form_fields", label="formulář"),
StreamFieldPanel("content_after"),
StreamFieldPanel("content_landing"),
]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(help.build(help.NO_SEO_TITLE, help.NO_SEARCH_IMAGE)),
],
gettext_lazy("Common page configuration"),
),
]
submissions_panels = [
FormSubmissionsPanel(),
]
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading=gettext_lazy("Content")),
ObjectList(promote_panels, heading=gettext_lazy("Promote")),
ObjectList(submissions_panels, heading="Data z formuláře"),
]
)
### RELATIONS
parent_page_types = [
"uniweb.UniwebHomePage",
"uniweb.UniwebFlexiblePage",
"uniweb.UniwebFormPage",
]
subpage_types = ["uniweb.UniwebFlexiblePage", "uniweb.UniwebFormPage"]
### OTHERS
class Meta:
verbose_name = "Formulářová stránka"