-
jan.bednarik authoredjan.bednarik authored
models.py 14.53 KiB
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.db import models
from django.utils.translation import gettext_lazy
from wagtail.admin.edit_handlers import (
CommentPanel,
FieldPanel,
HelpPanel,
MultiFieldPanel,
PublishingPanel,
StreamFieldPanel,
)
from wagtail.core import blocks
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core.models import Page
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtailmetadata.models import MetadataPageMixin
from calendar_utils.models import CalendarMixin
from shared.models import SubpageMixin
from tuning import admin_help
HELP_COMBINED_TITLE = (
"Pokud není zadán <strong>Titulek stránky</strong>, použije se "
"<strong>Název</strong> (tab obsah) doplněný o jméno kandidáta."
)
class MetaMixin:
def get_meta_title(self):
if self.seo_title:
return self.seo_title
return f"{self.title} | {self.root_page.full_name}"
class ContactBlock(blocks.StructBlock):
name = blocks.CharBlock(label="jméno")
job = blocks.CharBlock(label="pozice", required=False)
phone = blocks.CharBlock(label="telefon", required=False)
email = blocks.EmailBlock(label="email", required=False)
photo = ImageChooserBlock(label="fotka")
class Meta:
icon = "person"
label = "kontaktní osoba"
class SenatCampaignHomePage(Page, MetadataPageMixin, CalendarMixin):
### FIELDS
# top section
headline = models.CharField("podtitulek pod jménem", max_length=250, blank=True)
top_photo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
verbose_name="hlavní fotka",
)
claim = models.CharField("slogan pod fotkou", max_length=250, blank=True, null=True)
# about
about_left = RichTextField(
"kdo jsem (levý sloupec)",
blank=True,
features=["h4", "bold", "italic", "ol", "ul", "link", "document-link"],
)
about_right = RichTextField(
"kdo jsem (pravý sloupec)",
blank=True,
features=["h4", "bold", "italic", "ol", "ul", "link", "document-link"],
)
about_gallery = StreamField(
[("photo", ImageChooserBlock(label="fotka"))],
verbose_name="kdo jsem - galerie",
blank=True,
)
# financials
financials = StreamField(
[
(
"link",
blocks.StructBlock(
[
("label", blocks.CharBlock(label="název")),
("url", blocks.URLBlock(label="odkaz")),
],
label="odkaz",
),
),
(
"document",
blocks.StructBlock(
[
("label", blocks.CharBlock(label="název")),
("doc", DocumentChooserBlock(label="dokument")),
],
label="dokument",
),
),
],
verbose_name="transparentní financování",
blank=True,
)
# settings
first_name = models.CharField("jméno", max_length=250)
last_name = models.CharField("příjmení", max_length=250)
degree_before = models.CharField(
"titul před jménem", max_length=250, blank=True, null=True
)
degree_after = models.CharField(
"titul za jménem", max_length=250, blank=True, null=True
)
facebook = models.URLField("Facebook URL", blank=True, null=True)
instagram = models.URLField("Instagram URL", blank=True, null=True)
twitter = models.URLField("Twitter URL", blank=True, null=True)
linkedin = models.URLField("LinkedIn URL", blank=True, null=True)
contacts = StreamField(
[("item", ContactBlock())], verbose_name="kontaktní osoby", blank=True
)
matomo_id = models.IntegerField(
"Matomo ID pro sledování návštěvnosti", blank=True, null=True
)
### PANELS
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("degree_before"),
FieldPanel("first_name"),
FieldPanel("last_name"),
FieldPanel("degree_after"),
FieldPanel("headline"),
],
heading="úvod",
),
MultiFieldPanel(
[
ImageChooserPanel("top_photo"),
FieldPanel("claim"),
],
heading="úvodní foto",
),
MultiFieldPanel(
[
FieldPanel("about_left", classname="full"),
FieldPanel("about_right", classname="full"),
StreamFieldPanel("about_gallery"),
],
heading="kdo jsem",
),
StreamFieldPanel("financials"),
]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(
admin_help.build(
admin_help.IMPORTANT_TITLE,
"Pokud není zadán <strong>Search image</strong>, použije se úvodní foto kandidáta.",
)
),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [
MultiFieldPanel(
[
FieldPanel("facebook"),
FieldPanel("instagram"),
FieldPanel("twitter"),
FieldPanel("linkedin"),
],
heading="Sociální sítě",
),
FieldPanel("calendar_url"),
FieldPanel("matomo_id"),
StreamFieldPanel("contacts"),
CommentPanel(),
]
### RELATIONS
subpage_types = [
"senat_campaign.SenatCampaignNewsIndexPage",
"senat_campaign.SenatCampaignProgramPage",
"senat_campaign.SenatCampaignCookiesPage",
]
### OTHERS
# flag for rendering anchor links in menu
is_home = True
class Meta:
verbose_name = "Senát kampaň"
@property
def root_page(self):
return self
def get_meta_image(self):
return self.search_image or self.top_photo
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
@property
def has_program(self):
return self.get_descendants().type(SenatCampaignProgramPage).live().exists()
@property
def has_news(self):
return self.get_descendants().type(SenatCampaignNewsIndexPage).live().exists()
@property
def has_calendar(self):
return self.calendar_id is not None
@property
def has_donations(self):
# TODO
return False
@property
def cookies_page_url(self):
try:
return (
self.get_descendants()
.type(SenatCampaignCookiesPage)
.live()
.get()
.get_url()
)
except Page.DoesNotExist:
return "#"
def get_context(self, request):
context = super().get_context(request)
# get news
context["articles"] = (
self.get_descendants()
.type(SenatCampaignNewsPage)
.live()
.order_by("-senatcampaignnewspage__date")[:3]
)
try:
context["news_url"] = (
self.get_children()
.type(SenatCampaignNewsIndexPage)
.live()
.get()
.get_url(request)
)
except Page.DoesNotExist:
context["news_url"] = "#"
# get page with program
try:
context["program_page"] = (
self.get_children()
.type(SenatCampaignProgramPage)
.live()
.specific()
.get()
)
except Page.DoesNotExist:
context["program_page"] = None
return context
class SenatCampaignNewsIndexPage(Page, SubpageMixin, MetaMixin, MetadataPageMixin):
### FIELDS
### PANELS
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(
admin_help.build(HELP_COMBINED_TITLE, admin_help.NO_SEARCH_IMAGE)
),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [CommentPanel()]
### RELATIONS
parent_page_types = ["senat_campaign.SenatCampaignHomePage"]
subpage_types = ["senat_campaign.SenatCampaignNewsPage"]
### OTHERS
# flag for rendering anchor links in menu
is_home = False
class Meta:
verbose_name = "Aktuality"
def get_context(self, request):
context = super().get_context(request)
articles = self.get_children().live().order_by("-senatcampaignnewspage__date")
paginator = Paginator(articles, 4)
page = request.GET.get("page")
try:
articles = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
articles = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
articles = paginator.page(paginator.num_pages)
context["articles"] = articles
return context
class SenatCampaignNewsPage(Page, SubpageMixin, MetaMixin, MetadataPageMixin):
### FIELDS
date = models.DateField("datum")
perex = models.TextField("perex")
body = RichTextField("článek", blank=True)
photo = models.ForeignKey(
"wagtailimages.Image",
verbose_name="fotka",
on_delete=models.PROTECT,
null=True,
blank=True,
)
# we will use photo as search image
search_image = None
### PANELS
content_panels = Page.content_panels + [
FieldPanel("date"),
FieldPanel("perex"),
FieldPanel("body", classname="full"),
ImageChooserPanel("photo"),
]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
HelpPanel(
admin_help.build(
HELP_COMBINED_TITLE,
"Pokud není zadán <strong>Popis vyhledávání</strong>, použije se prvních 150 znaků <strong>Perexu</strong> (tab obsah).",
)
),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [PublishingPanel(), CommentPanel()]
### RELATIONS
parent_page_types = ["senat_campaign.SenatCampaignNewsIndexPage"]
subpage_types = []
### OTHERS
# flag for rendering anchor links in menu
is_home = False
class Meta:
verbose_name = "Aktualita"
def get_context(self, request):
context = super().get_context(request)
context["related_articles"] = (
self.get_siblings(inclusive=False)
.live()
.order_by("-senatcampaignnewspage__date")[:3]
)
return context
@property
def root_page(self):
if not hasattr(self, "_root_page"):
self._root_page = (
self.get_ancestors().type(SenatCampaignHomePage).specific().get()
)
return self._root_page
def get_meta_image(self):
return self.photo
def get_meta_description(self):
if self.search_description:
return self.search_description
if len(self.perex) > 150:
return str(self.perex)[:150] + "..."
return self.perex
class ProgramBlock(blocks.StructBlock):
title = blocks.CharBlock(label="titulek")
perex = blocks.TextBlock(label="perex na úvodní stránku")
body = blocks.RichTextBlock(label="text bodu")
image = ImageChooserBlock(label="ilustrační obrázek")
class Meta:
icon = "doc-full"
label = "programový bod"
class SenatCampaignProgramPage(Page, SubpageMixin, MetaMixin, MetadataPageMixin):
### FIELDS
committee_preference = StreamField(
[("committee", blocks.CharBlock(label="výbor či komise"))],
verbose_name="preferované výbory a komise",
blank=True,
)
content = StreamField(
[("item", ProgramBlock())], verbose_name="programové body", blank=True
)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("committee_preference"),
StreamFieldPanel("content"),
]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(
admin_help.build(HELP_COMBINED_TITLE, admin_help.NO_SEARCH_IMAGE)
),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [CommentPanel()]
### RELATIONS
parent_page_types = ["senat_campaign.SenatCampaignHomePage"]
subpage_types = []
### OTHERS
# flag for rendering anchor links in menu
is_home = False
class Meta:
verbose_name = "Program"
class SenatCampaignCookiesPage(Page, SubpageMixin, MetaMixin, MetadataPageMixin):
### FIELDS
body = RichTextField("obsah", blank=True)
### PANELS
content_panels = Page.content_panels + [
FieldPanel("body", classname="full"),
]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
HelpPanel(
admin_help.build(HELP_COMBINED_TITLE, admin_help.NO_SEARCH_IMAGE)
),
],
gettext_lazy("Common page configuration"),
),
]
settings_panels = [CommentPanel()]
### RELATIONS
parent_page_types = ["senat_campaign.SenatCampaignHomePage"]
subpage_types = []
### OTHERS
# flag for rendering anchor links in menu
is_home = False
class Meta:
verbose_name = "Cookies"