from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.db import models from django.utils.translation import gettext_lazy from wagtail import blocks from wagtail.admin.panels import ( CommentPanel, FieldPanel, HelpPanel, MultiFieldPanel, PublishingPanel, ) from wagtail.documents.blocks import DocumentChooserBlock from wagtail.fields import RichTextField, StreamField from wagtail.images.blocks import ImageChooserBlock from wagtail.models import Page from wagtailmetadata.models import MetadataPageMixin from calendar_utils.models import CalendarMixin from shared.models import ( ExtendedMetadataHomePageMixin, ExtendedMetadataPageMixin, SubpageMixin, ) from shared_legacy.models import FooterMixin 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 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, ExtendedMetadataHomePageMixin, MetadataPageMixin, FooterMixin, 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, use_json_field=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, use_json_field=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 ) donations_url = models.URLField("URL darovací kampaně", 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, use_json_field=True, ) matomo_id = models.IntegerField( "Matomo ID pro sledování návštěvnosti", blank=True, null=True ) footer_extra_content = RichTextField( verbose_name="Extra obsah pod šedou patičkou", blank=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( [ FieldPanel("top_photo"), FieldPanel("claim"), ], heading="úvodní foto", ), MultiFieldPanel( [ FieldPanel("about_left"), FieldPanel("about_right"), FieldPanel("about_gallery"), ], heading="kdo jsem", ), FieldPanel("financials"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("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("donations_url"), FieldPanel("matomo_id"), FieldPanel("title_suffix"), FieldPanel("meta_title_suffix"), FieldPanel("contacts"), FieldPanel("footer_extra_content"), FieldPanel("footer_links"), 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): return self.donations_url is not None @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, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin ): ### FIELDS ### PANELS promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("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, ExtendedMetadataPageMixin, SubpageMixin, 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"), FieldPanel("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, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin ): ### FIELDS committee_preference = StreamField( [("committee", blocks.CharBlock(label="výbor či komise"))], verbose_name="preferované výbory a komise", blank=True, use_json_field=True, ) content = StreamField( [("item", ProgramBlock())], verbose_name="programové body", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("committee_preference"), FieldPanel("content"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("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, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin ): ### FIELDS body = RichTextField("obsah", blank=True) ### PANELS content_panels = Page.content_panels + [ FieldPanel("body"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("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"