-
Alexa Valentová authoredAlexa Valentová authored
models.py 27.62 KiB
import random
from captcha.fields import CaptchaField
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 import blocks
from wagtail.admin.panels import (
FieldPanel,
InlinePanel,
MultiFieldPanel,
ObjectList,
PageChooserPanel,
TabbedInterface,
)
from wagtail.contrib.forms.models import AbstractForm, AbstractFormField
from wagtail.contrib.forms.panels import FormSubmissionsPanel
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
from wagtail.contrib.table_block.blocks import TableBlock
from wagtail.fields import RichTextField, StreamField
from wagtail.images.blocks import ImageChooserBlock
from wagtail.models import Page
from wagtail.search import index
from wagtailmetadata.models import MetadataPageMixin
from calendar_utils.models import CalendarMixin
from shared.blocks import (
AdvancedTextBlock,
ChartBlock,
GalleryBlock,
HeadlineBlock,
NewsletterSubscriptionBlock,
PictureHeadlineBlock,
)
from shared.const import RICH_TEXT_DEFAULT_FEATURES
from shared.models import (
ArticleMixin,
ArticlesPageMixin,
CalendarMixin,
ExtendedMetadataPageMixin,
MainHomePageMixin,
MainMenuMixin,
MainSearchPageMixin,
PdfPageMixin,
SharedTaggedUniwebArticle,
SocialMixin,
SubpageMixin,
)
from shared_legacy.blocks import FlipCardsBlock
from shared_legacy.models import FooterMixin as LegacyFooterMixin
from shared_legacy.utils import make_promote_panels, strip_all_html_tags, trim_to_length
from tuning import admin_help
from .blocks import AlignedTableBlock, PeopleGroupListBlock, PersonUrlBlock
from .constants import (
ALIGN_CHOICES,
ALIGN_CSS,
ARTICLES_PER_LINE,
ARTICLES_PER_PAGE,
BLACK_ON_WHITE,
CALENDAR_EVENTS_CHOICES,
COLOR_CHOICES,
COLOR_CSS,
FUTURE,
LEFT,
)
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)
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_DEFAULT_FEATURES
)
right_text = blocks.RichTextBlock(
label="pravý sloupec", features=RICH_TEXT_DEFAULT_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_DEFAULT_FEATURES
)
right_text = blocks.RichTextBlock(
label="pravý sloupec", features=RICH_TEXT_DEFAULT_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 PictureListBlock(ColorBlock):
items = blocks.ListBlock(
blocks.RichTextBlock(label="odstavec", features=RICH_TEXT_DEFAULT_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
articles_page = value["page"]
context["articles"] = articles_page.materialize_shared_articles_query(
articles_page.append_all_shared_articles_query(
UniwebArticlePage.objects.child_of(articles_page)
)[: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",
"uniweb.UniwebPeoplePage",
"uniweb.UniwebPersonPage",
"uniweb.UniwebPdfPage",
"district.DistrictPersonPage",
],
)
class Meta:
label = "stránka"
class CalendarAgendaBlock(blocks.StructBlock):
info = blocks.StaticBlock(
label="volba kalendáře",
admin_text="adresa kalendáře se zadává v nastavení hlavní stránky webu",
)
count = blocks.IntegerBlock(label="maximum událostí k zobrazení", default=10)
event_type = blocks.ChoiceBlock(
CALENDAR_EVENTS_CHOICES,
label="druh událostí",
default=FUTURE,
)
class Meta:
label = "kalendář agenda"
icon = "date"
group = "ostatní"
template = "uniweb/blocks/calendar_agenda.html"
def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context=parent_context)
count = value["count"]
page = context.get("page")
if page and page.root_page.has_calendar:
if value["event_type"] == FUTURE and page.root_page.calendar.future_events:
context["events"] = page.root_page.calendar.future_events[:count]
elif page.root_page.calendar.past_events:
context["events"] = page.root_page.calendar.past_events[:count]
else:
context["events"] = []
else:
context["events"] = []
return context
class ButtonBlock(blocks.StructBlock):
text = blocks.CharBlock(label="Nadpis")
url = blocks.URLBlock(
label="Odkaz",
help_text="Pokud je odkaz vyplněný, není nutno vyplňovat stránku.",
required=False,
)
page = blocks.PageChooserBlock(
label="Stránka",
help_text="Pokud je stránka vyplněná, není nutno vyplňovat odkaz.",
required=False,
)
class Meta:
label = "Tlačítko"
icon = "link-external"
group = "ostatní"
template = "uniweb/blocks/button.html"
CONTENT_STREAM_BLOCKS = [
# title, advanced_title
("headline", HeadlineBlock()),
# picture_title
("picture_title", PictureHeadlineBlock()),
# text
(
"text",
blocks.RichTextBlock(
label="Textový editor",
features=RICH_TEXT_DEFAULT_FEATURES,
template="styleguide2/includes/atoms/text/prose_richtext.html",
),
),
# advanced_text
("advanced_text", AdvancedTextBlock()),
# text_columns
("text_columns", ColumnsTextBlock()),
# advanced_text_columns
# gallery
("new_gallery", GalleryBlock()),
# picture_list
# aligned_table
(
"aligned_table",
AlignedTableBlock(
group="ostatní",
template="styleguide2/includes/atoms/table/aligned_table.html",
),
),
# table
(
"table",
TableBlock(
label="Tabulka",
group="ostatní",
template="styleguide2/includes/atoms/table/table.html",
),
),
# articles
# calendar_agenda
# button
# chart
("chart", ChartBlock()),
# cards
(
"title",
blocks.CharBlock(
label="nadpis",
icon="title",
group="nadpisy",
template="uniweb/blocks/title.html",
),
),
("advanced_title", AdvancedTitleBlock()),
# (
# "text",
# blocks.RichTextBlock(
# label="Textový editor",
# features=RICH_TEXT_DEFAULT_FEATURES,
# template="styleguide2/includes/atoms/text/prose_richtext.html",
# ),
# ),
("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()),
("articles", ArticlesBlock()),
("calendar_agenda", CalendarAgendaBlock()),
("button", ButtonBlock()),
("cards", FlipCardsBlock(template="uniweb/blocks/flip_cards.html")),
]
class UniwebArticleTag(TaggedItemBase):
content_object = ParentalKey(
"uniweb.UniwebArticlePage",
on_delete=models.CASCADE,
related_name="tagged_items",
)
class UniwebHomePage(CalendarMixin, LegacyFooterMixin, MainHomePageMixin):
### FIELDS
fallback_image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
verbose_name="Obrázek pro pozadí stránek",
help_text="Tento obrázek bude využit např. jako pozadí pro osobní stránky.",
)
calendar_page = models.ForeignKey(
"UniwebCalendarPage",
verbose_name="Stránka s kalendářem",
on_delete=models.PROTECT,
null=True,
blank=True,
)
content = StreamField(
CONTENT_STREAM_BLOCKS + [("newsletter", NewsletterSubscriptionBlock())],
verbose_name="obsah stránky",
blank=True,
use_json_field=True,
)
# settings
matomo_id = models.IntegerField(
"Matomo ID pro sledování návštěvnosti",
blank=True,
null=True,
)
logo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
verbose_name="Logo pro web",
help_text="Pokud žádné nezadáte, použije se default logo pirátů",
related_name="uniweb_logo_image",
)
top_menu = StreamField(
[("item", MenuItemBlock())],
verbose_name="horní menu",
blank=True,
use_json_field=True,
)
narrow_layout = models.BooleanField(
"zúžený obsah stránky",
default=False,
help_text="užší stránka je vhodná pro lepší čitelnost textů",
)
### Header
menu_button_name = models.CharField(
verbose_name="Text na tlačítku pro zapojení",
max_length=16,
blank=True,
null=True,
)
### Footer
hide_footer = models.BooleanField(
"skrýt patičku", default=False, help_text="Chcete skrýt patičku?"
)
show_logo = models.BooleanField(
"zobrazit logo", default=True, help_text="Zobrazit logo"
)
show_social_links = models.BooleanField(
"zobrazit soc. linky", default=True, help_text="Zobrazit link na sociální sítě"
)
show_pirate_buttons = models.BooleanField(
"zobrazit pirátská tlačítka",
default=True,
help_text="Zobrazit pirátská tlačítka",
)
footer_extra_content = RichTextField(
verbose_name="Extra obsah pod šedou patičkou",
blank=True,
features=RICH_TEXT_DEFAULT_FEATURES,
)
donation_page = models.URLField(
"URL pro příjem darů (tlačítko Darovat)",
blank=True,
null=True,
default="https://dary.pirati.cz",
)
### PANELS
settings_panels = [
FieldPanel("logo"),
MultiFieldPanel(
[
FieldPanel("matomo_id"),
FieldPanel("title_suffix"),
FieldPanel("narrow_layout"),
FieldPanel("fallback_image"),
],
"Obecné nastavení webu",
),
MultiFieldPanel(
[
FieldPanel("calendar_url"),
PageChooserPanel("calendar_page"),
],
"Kalendář",
),
MultiFieldPanel(
[
FieldPanel("hide_footer"),
FieldPanel("show_logo"),
FieldPanel("show_social_links"),
FieldPanel("show_pirate_buttons"),
FieldPanel("donation_page"),
],
"Patička",
),
]
menu_panels = (
MainMenuMixin.menu_panels
+ SocialMixin.menu_panels
+ [
FieldPanel("menu_button_name"),
FieldPanel("menu_button_content"),
]
)
edit_handler = TabbedInterface(
[
ObjectList(MainHomePageMixin.content_panels, heading="Obsah"),
ObjectList(menu_panels, heading="Hlavička"),
ObjectList(MainHomePageMixin.footer_panels, heading="Patička"),
ObjectList(MainHomePageMixin.promote_panels, heading="Propagace"),
ObjectList(settings_panels, heading="Nastavení"),
]
)
### RELATIONS
subpage_types = [
"uniweb.UniwebFlexiblePage",
"uniweb.UniwebArticlesIndexPage",
"uniweb.UniwebFormPage",
"uniweb.UniwebPeoplePage",
"uniweb.UniwebCalendarPage",
"uniweb.UniwebSearchPage",
]
### OTHERS
class Meta:
verbose_name = "Univerzální web"
@property
def gdpr_and_cookies_page(self):
from main.models import MainHomePage
return MainHomePage.objects.first().gdpr_and_cookies_page
@property
def article_page_model(self):
return UniwebArticlePage
@property
def articles_page_model(self):
return UniwebArticlesIndexPage
@property
def search_page_model(self):
return UniwebSearchPage
@property
def root_page(self):
return self
@property
def has_calendar(self):
return self.calendar_id is not None
class UniwebFlexiblePage(
Page,
ExtendedMetadataPageMixin,
SubpageMixin,
MetadataPageMixin,
):
### FIELDS
content = StreamField(
CONTENT_STREAM_BLOCKS + [("newsletter", NewsletterSubscriptionBlock())],
verbose_name="obsah stránky",
blank=True,
use_json_field=True,
)
### PANELS
promote_panels = make_promote_panels()
content_panels = Page.content_panels + [
FieldPanel("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 UniwebCalendarPage(SubpageMixin, MetadataPageMixin, CalendarMixin, Page):
"""
Page for displaying full calendar
"""
### PANELS
content_panels = Page.content_panels + [FieldPanel("calendar_url")]
### RELATIONS
parent_page_types = [
"uniweb.UniwebHomePage",
]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Stránka s kalendářem"
class UniwebArticlesIndexPage(
RoutablePageMixin,
Page,
ExtendedMetadataPageMixin,
SubpageMixin,
MetadataPageMixin,
ArticlesPageMixin,
):
### FIELDS
### PANELS
content_panels = ArticlesPageMixin.content_panels
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["uniweb.UniwebHomePage"]
subpage_types = ["uniweb.UniwebArticlePage"]
### OTHERS
class Meta:
verbose_name = "Sekce článků"
@route(r"^sdilene/$", name="shared")
def shared(self, request):
return self.setup_article_page_context(request)
def get_context(self, request):
context = super().get_context(request)
num = request.GET.get("page", 1)
tag = request.GET.get("tag")
tag_params = self.filter_by_tag_name(tag)
own_children = UniwebArticlePage.objects.child_of(self)
articles = self.append_all_shared_articles_query(
own_children if tag is None else own_children.filter(**tag_params),
custom_article_query=lambda articles: articles.filter(**tag_params)
if tag is not None
else articles,
)
context["articles"] = self.get_page_with_shared_articles(
articles,
ARTICLES_PER_PAGE,
num,
)
context["tags"] = self.search_tags_by_unioned_id_query(articles)
context["active_tag"] = tag
return context
class UniwebArticlePage(
ArticleMixin, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
tags = ClusterTaggableManager(through=UniwebArticleTag, blank=True)
shared_tags = ClusterTaggableManager(
verbose_name="Tagy pro sdílení mezi weby",
through=SharedTaggedUniwebArticle,
blank=True,
)
search_fields = ArticleMixin.search_fields + [
index.FilterField("slug"),
]
### PANELS
content_panels = ArticleMixin.content_panels + [
FieldPanel("tags"),
FieldPanel("shared_tags"),
]
promote_panels = make_promote_panels(
admin_help.build(admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX),
search_image=False,
)
### RELATIONS
parent_page_types = ["uniweb.UniwebArticlesIndexPage"]
subpage_types = ["uniweb.UniwebPdfPage"]
### 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__timestamp")[:3]
)
if self.shared_from is None
else []
)
return context
class UniwebFormField(AbstractFormField):
page = ParentalKey(
"UniwebFormPage", on_delete=models.CASCADE, related_name="form_fields"
)
class UniwebFormPage(
AbstractForm, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin
):
### FIELDS
content_before = StreamField(
CONTENT_STREAM_BLOCKS,
verbose_name="obsah stránky před formulářem",
blank=True,
use_json_field=True,
)
content_after = StreamField(
CONTENT_STREAM_BLOCKS,
verbose_name="obsah stránky za formulářem",
blank=True,
use_json_field=True,
)
content_landing = StreamField(
CONTENT_STREAM_BLOCKS,
verbose_name="obsah stránky zobrazené po odeslání formuláře",
blank=True,
use_json_field=True,
)
### PANELS
content_panels = AbstractForm.content_panels + [
FieldPanel("content_before"),
InlinePanel("form_fields", label="formulář"),
FieldPanel("content_after"),
FieldPanel("content_landing"),
]
promote_panels = make_promote_panels()
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"
def get_form_class(self):
form = super().get_form_class()
form.base_fields["captcha"] = CaptchaField(label="opište písmena z obrázku")
return form
# Don't waste time making a new mixin for this,
# we'll be doing Octopus imports within a short while.
class UniwebPersonPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
job = models.CharField(
"Povolání",
max_length=128,
blank=True,
null=True,
help_text="Např. 'Informatik'",
)
job_function = models.CharField(
"Funkce", max_length=128, blank=True, null=True, help_text="Např. 'Předseda'"
)
background_photo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
verbose_name="obrázek do záhlaví",
)
profile_photo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
verbose_name="profilová fotka",
)
text = RichTextField("text", blank=True, features=RICH_TEXT_DEFAULT_FEATURES)
email = models.EmailField("Email", null=True, blank=True)
show_email = models.BooleanField("Zobrazovat email na stránce?", default=True)
phone = models.CharField("Telefon", max_length=16, blank=True, null=True)
city = models.CharField("Město/obec", max_length=64, blank=True, null=True)
age = models.IntegerField("Věk", blank=True, null=True)
is_pirate = models.BooleanField("Je členem Pirátské strany?", default=True)
other_party = models.CharField(
"Strana",
max_length=64,
blank=True,
null=True,
help_text="Vyplňte pokud osoba není Pirát",
)
other_party_logo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
verbose_name="Logo strany",
help_text="Vyplňte pokud osoba není Pirát",
)
facebook_url = models.URLField("Odkaz na Facebook", blank=True, null=True)
instagram_url = models.URLField("Odkaz na Instagram", blank=True, null=True)
twitter_url = models.URLField("Odkaz na Twitter", blank=True, null=True)
youtube_url = models.URLField("Odkaz na Youtube kanál", blank=True, null=True)
flickr_url = models.URLField("Odkaz na Flickr", blank=True, null=True)
custom_web_url = models.URLField("Odkaz na vlastní web", blank=True, null=True)
other_urls = StreamField(
[("other_url", PersonUrlBlock())],
verbose_name="Další odkaz",
blank=True,
use_json_field=True,
)
### PANELS
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("job"),
FieldPanel("job_function"),
],
"Základní údaje",
),
MultiFieldPanel(
[
FieldPanel("profile_photo"),
FieldPanel("background_photo"),
],
"Fotky",
),
FieldPanel("text"),
MultiFieldPanel(
[
FieldPanel("email"),
FieldPanel("show_email"),
FieldPanel("phone"),
FieldPanel("city"),
FieldPanel("age"),
FieldPanel("is_pirate"),
FieldPanel("other_party"),
FieldPanel("other_party_logo"),
],
"Kontaktní informace",
),
MultiFieldPanel(
[
FieldPanel("facebook_url"),
FieldPanel("instagram_url"),
FieldPanel("twitter_url"),
FieldPanel("youtube_url"),
FieldPanel("flickr_url"),
FieldPanel("custom_web_url"),
FieldPanel("other_urls"),
],
"Sociální sítě",
),
]
settings_panels = []
### RELATIONS
parent_page_types = ["uniweb.UniwebPeoplePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Detail osoby"
ordering = ("title",)
def get_background_photo(self):
"""
Vrací background_photo pro pozadí na stránce, pokud není nastaveno,
vezme falbback z homepage
"""
return (
self.background_photo
if self.background_photo
else self.root_page.fallback_image
)
def get_job_description(self):
"""
Vrací povolání + funkci, s čárkou mezi nima, pokud jsou obě definovaná, jinak vrátí jednu z nich
"""
if self.job and self.job_function:
return f"{self.job}, {self.job_function}"
return self.job or self.job_function or ""
def get_context(self, request):
context = super().get_context(request)
# Na strance detailu cloveka se vpravo zobrazuji 3 dalsi nahodne profily
context["random_people"] = list(
self.get_siblings(inclusive=False).live().specific()
)
random.shuffle(context["random_people"])
context["random_people"] = context["random_people"][:3]
return context
def get_meta_image(self):
return self.search_image or self.profile_photo
def get_meta_description(self):
if self.search_description:
return self.search_description
if self.text:
return trim_to_length(strip_all_html_tags(self.text))
return None
class UniwebPeoplePage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
content = StreamField(
[
(
"text",
blocks.RichTextBlock(
label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
),
),
("people_group", PeopleGroupListBlock()),
],
verbose_name="Obsah stránky",
blank=True,
use_json_field=True,
)
### PANELS
content_panels = Page.content_panels + [FieldPanel("content")]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["uniweb.UniwebHomePage"]
subpage_types = ["uniweb.UniwebPersonPage"]
### OTHERS
class Meta:
verbose_name = "Lidé"
class UniwebPdfPage(MetadataPageMixin, SubpageMixin, Page, PdfPageMixin):
"""
Single pdf page display
"""
### RELATIONS
parent_page_types = [
"uniweb.UniwebHomePage",
"uniweb.UniwebArticlePage",
]
subpage_types = []
### PANELS
content_panels = Page.content_panels + PdfPageMixin.content_panels
### OTHER
class Meta:
verbose_name = "PDF stránka"
class UniwebSearchPage(MainSearchPageMixin):
### RELATIONS
parent_page_types = ["uniweb.UniwebHomePage"]