import json import re from functools import cached_property from django import forms from django.conf import settings from django.core.paginator import Paginator from django.db import models from django.db.models.functions import Greatest from django.http import HttpResponseRedirect from django.utils.text import slugify from django.utils.timezone import localtime 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 ( CommentPanel, FieldPanel, HelpPanel, MultiFieldPanel, ObjectList, PageChooserPanel, PublishingPanel, TabbedInterface, ) from wagtail.blocks import RichTextBlock from wagtail.contrib.routable_page.models import RoutablePageMixin, route from wagtail.documents.blocks import DocumentChooserBlock 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.forms import SubscribeForm from shared.models import SubpageMixin from shared.models.legacy import ArticleMixin from shared.utils import get_subpage_url, subscribe_to_newsletter from tuning import admin_help from .constants import ( AGE_30_49, ARTICLE_RICH_TEXT_FEATURES, ARTICLES_PER_PAGE, BENEFITS_CHOICES, CANDIDATE_RICH_TEXT_FEATURES, CHILDLESS, COUNTRYSIDE, CULTURE, EDUCATION, EXTRA_FEATURES, HEALTH, HOUSING, MATURE, MINISTRY_AGRICULTURE, MINISTRY_ARCHETYPES, MINISTRY_BUSINESS, MINISTRY_CHOICES, MINISTRY_CODES, MINISTRY_COUNTRYSIDE, MINISTRY_CULTURE, MINISTRY_DEFENSE, MINISTRY_ENVIRONMENT, MINISTRY_FINANCES, MINISTRY_FOREIGN, MINISTRY_HEALTH, MINISTRY_INTERIOR, MINISTRY_JUSTICE, MINISTRY_OPTIONS, MINISTRY_SCHOOLS, MINISTRY_SOCIAL, MINISTRY_TRANSPORT, NATURE, OCCUPATION_BUSINESS, OCCUPATION_WORKING, PARENTS, PARTY_CHOICES, PARTY_NAME, PIRATES, PLAN_ARCHETYPES, PLAN_CARE, PLAN_CHOICES, PLAN_CLIMATE, PLAN_CORRUPTION, PLAN_COUNTRYSIDE, PLAN_DIGITAL, PLAN_ECONOMICS, PLAN_MANAGEMENT, PLAN_OPTIONS, PLAN_SAFE_COUNTRY, PROGRAM_POINTS_PER_PAGE, REGION_CHOICES, REGION_NAME_VARIANT, REGION_OPTIONS, REGION_SLUGS, RESTRICTED_FEATURES, SENIORS, SPORT, STANDARD_FEATURES, STRATEGIC_PER_PAGE, STRATEGIC_RICH_TEXT_FEATURES, STUDENTS, STYLE_CHOICES, STYLE_CSS, TECHNOLOGY, TOP_CANDIDATES_NUM, WEALTH_AVERAGE, WEALTH_BAD, WHITE, WORKING_SENIORS, ) from .forms import ProgramAppForm, ProgramPointPageForm from .utils import get_archetype NO_SEARCH_IMAGE_USE_PHOTO = ( "Pokud není zadán <strong>Search image</strong>, použije se <strong>hlavní " "fotka</strong> (tab obsah)." ) class LinkBlock(blocks.StructBlock): title = blocks.CharBlock(label="titulek") url = blocks.URLBlock(label="odkaz") class Meta: icon = "link-external" label = "odkaz" class MenuItemBlock(blocks.StructBlock): name = blocks.CharBlock(label="název") page = blocks.PageChooserBlock( label="stránka", page_type=[ "elections2021.Elections2021ArticlesPage", "elections2021.Elections2021CandidatesListPage", "elections2021.Elections2021CandidatesMapPage", "elections2021.Elections2021ProgramPage", "elections2021.Elections2021QuestionsPage", "elections2021.Elections2021ProgramAppPage", "elections2021.Elections2021TextPage", "elections2021.Elections2021StrategicListPage", "elections2021.Elections2021StrategicPage", "elections2021.Elections2021MythsPage", "elections2021.Elections2021DownloadsPage", "elections2021.Elections2021GovernmentTeamPage", "elections2021.Elections2021CalendarPage", "elections2021.Elections2021ProgramInNutshellPage", "elections2021.Elections2021GoingToVotePage", ], ) class Meta: label = "stránka" class SlideBlock(blocks.StructBlock): title = blocks.CharBlock(label="titulek") photo = ImageChooserBlock(label="fotka") button_label = blocks.CharBlock(label="text tlačítka") page = blocks.PageChooserBlock( label="stránka do tlačítka", page_type=[ "elections2021.Elections2021ArticlesPage", "elections2021.Elections2021CandidatesListPage", "elections2021.Elections2021CandidatesMapPage", "elections2021.Elections2021ProgramPage", "elections2021.Elections2021QuestionsPage", "elections2021.Elections2021ProgramAppPage", "elections2021.Elections2021TextPage", "elections2021.Elections2021StrategicListPage", "elections2021.Elections2021StrategicPage", "elections2021.Elections2021MythsPage", "elections2021.Elections2021DownloadsPage", "elections2021.Elections2021GovernmentTeamPage", "elections2021.Elections2021CalendarPage", ], required=False, ) raw_url = blocks.CharBlock( label="ručně zadaný odkaz do tlačítka (místo stránky)", required=False ) class Meta: label = "slide" icon = "media" template = "elections2021/_carousel_slide.html" class Elections2021HomePage(MetadataPageMixin, RoutablePageMixin, Page): ### FIELDS carousel = StreamField( [("slide", SlideBlock())], verbose_name="obsah slideru", blank=True, use_json_field=True, ) elections_date = models.DateTimeField("datum začátku voleb", blank=True, null=True) header_links = StreamField( [("link", LinkBlock())], verbose_name="odkazy v záhlaví", blank=True, use_json_field=True, ) footer_links = StreamField( [("link", LinkBlock())], verbose_name="odkazy v zápatí", blank=True, use_json_field=True, ) footer_menu = StreamField( [("item", MenuItemBlock())], verbose_name="menu projděte si v zápatí", blank=True, use_json_field=True, ) gdpr_and_cookies_page = models.ForeignKey( "main.MainSimplePage", verbose_name="Stránka GDPR a Cookies", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) program_strategic_page = models.ForeignKey( "wagtailcore.Page", verbose_name="stránka program v kostce", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) program_silver_page = models.ForeignKey( "wagtailcore.Page", verbose_name="stránka stříbrný program", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) program_for_business = models.ForeignKey( "wagtailcore.Page", verbose_name="stránka program pro podnikatele", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) post_election_strategy = models.ForeignKey( "wagtailcore.Page", verbose_name="stránka povolební strategie", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) matomo_id = models.IntegerField( "Matomo ID pro sledování návštěvnosti", blank=True, null=True ) donate_page = models.ForeignKey( "wagtailcore.Page", verbose_name="stránka darovacího projektu", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) onboarding_url = models.URLField( "URL registrace dobrovolníků", null=True, blank=True ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("carousel"), FieldPanel("elections_date"), ] header_panels = [ FieldPanel("header_links"), PageChooserPanel( "program_strategic_page", [ "elections2021.Elections2021StrategicPage", "elections2021.Elections2021ProgramInNutshellPage", ], ), PageChooserPanel( "program_silver_page", "elections2021.Elections2021StrategicPage" ), PageChooserPanel( "program_for_business", "elections2021.Elections2021StrategicPage" ), PageChooserPanel( "post_election_strategy", "elections2021.Elections2021StrategicPage" ), ] footer_panels = [ FieldPanel("footer_menu"), FieldPanel("footer_links"), PageChooserPanel("gdpr_and_cookies_page", "main.MainSimplePage"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.IMPORTANT_TITLE)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [ FieldPanel("matomo_id"), PageChooserPanel("donate_page", "donate.DonateProjectPage"), FieldPanel("onboarding_url"), CommentPanel(), ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading=gettext_lazy("Content")), ObjectList(promote_panels, heading=gettext_lazy("Promote")), ObjectList(header_panels, heading="hlavička"), ObjectList(footer_panels, heading="patička"), ObjectList( settings_panels, heading=gettext_lazy("Settings"), classname="settings" ), ] ) ### RELATIONS subpage_types = [ "elections2021.Elections2021ArticlesPage", "elections2021.Elections2021CandidatesListPage", "elections2021.Elections2021CandidatesMapPage", "elections2021.Elections2021ProgramPage", "elections2021.Elections2021QuestionsPage", "elections2021.Elections2021ProgramAppPage", "elections2021.Elections2021TextPage", "elections2021.Elections2021StrategicListPage", "elections2021.Elections2021MythsPage", "elections2021.Elections2021DownloadsPage", "elections2021.Elections2021GovernmentTeamPage", "elections2021.Elections2021CalendarPage", "elections2021.Elections2021MapPage", "elections2021.Elections2021ProgramInNutshellPage", "elections2021.Elections2021GoingToVotePage", ] ### OTHERS class Meta: verbose_name = "Koaliční web 2021" @property def root_page(self): return self @cached_property def articles_page_url(self): return get_subpage_url(self, Elections2021ArticlesPage) @cached_property def candidates_list_page_url(self): try: return ( self.get_descendants() .type(Elections2021CandidatesListPage) .live() .specific() .first() .get_region_list_url() ) except (Page.DoesNotExist, AttributeError): return "#" @cached_property def candidates_map_page_url(self): return get_subpage_url(self, Elections2021CandidatesMapPage) @cached_property def questions_page_url(self): return get_subpage_url(self, Elections2021QuestionsPage) @cached_property def program_page_url(self): return get_subpage_url(self, Elections2021ProgramPage) @cached_property def program_app_page_url(self): return get_subpage_url(self, Elections2021ProgramAppPage) @cached_property def strategic_list_page_url(self): return get_subpage_url(self, Elections2021StrategicListPage) @cached_property def downloads_page_url(self): return get_subpage_url(self, Elections2021DownloadsPage) @cached_property def myths_page_url(self): return get_subpage_url(self, Elections2021MythsPage) @cached_property def government_team_page_url(self): return get_subpage_url(self, Elections2021GovernmentTeamPage) @cached_property def going_to_vote_page_url(self): return get_subpage_url(self, Elections2021GoingToVotePage) @cached_property def full_program_page_url(self): try: return ( self.get_descendants() .type(Elections2021ProgramPage) .live() .specific() .first() .get_full_program_url() ) except (Page.DoesNotExist, AttributeError): return "#" @cached_property def has_calendar(self): try: self.calendar return True except (Page.DoesNotExist, AttributeError): return False @cached_property def calendar_page_url(self): return get_subpage_url(self, Elections2021CalendarPage) @cached_property def calendar(self): return ( self.get_descendants() .type(Elections2021CalendarPage) .live() .specific() .first() .get_calendar() ) @cached_property def gdpr_and_cookies_url(self): if self.gdpr_and_cookies_page: return self.gdpr_and_cookies_page.url return "#" @cached_property def program_strategic_page_url(self): if self.program_strategic_page: return self.program_strategic_page.url return "#" @cached_property def program_silver_page_url(self): if self.program_silver_page: return self.program_silver_page.url return "#" @cached_property def program_for_business_url(self): if self.program_for_business: return self.program_for_business.url return "#" @cached_property def post_election_strategy_url(self): if self.post_election_strategy: return self.post_election_strategy.url return "#" @cached_property def newsletter_subscribe_url(self): return self.url + self.reverse_subpage("newsletter_subscribe") def get_context(self, request): context = super().get_context(request) context["articles"] = ( Elections2021ArticlePage.objects.live() .specific() .order_by("-timestamp")[:3] ) context["questions"] = ( Elections2021QuestionsPage.objects.live().specific().first().elections[:3] ) if self.elections_date: delta = self.elections_date - localtime() if delta.total_seconds() < 0: context["countdown_days"] = 0 context["countdown_hours"] = 0 else: days, reminder = divmod(delta.total_seconds(), 60 * 60 * 24) hours, reminder = divmod(reminder, 60 * 60) context["countdown_days"] = int(days) context["countdown_hours"] = int(hours) return context @route(r"^prihlaseni-k-newsletteru/$") def newsletter_subscribe(self, request): if request.method == "POST": form = SubscribeForm(request.POST) if form.is_valid(): subscribe_to_newsletter( form.cleaned_data["email"], settings.ELECTIONS2021_NEWSLETTER_CID ) try: page = ( Page.objects.filter(id=form.cleaned_data["return_page_id"]) .live() .first() ) return HttpResponseRedirect(page.full_url) except Page.DoesNotExist: return HttpResponseRedirect(self.url) return HttpResponseRedirect(self.url) class Elections2021ArticleTag(TaggedItemBase): content_object = ParentalKey( "elections2021.Elections2021ArticlePage", on_delete=models.CASCADE, related_name="tagged_items", ) class Elections2021ArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page): ### FIELDS content = StreamField( [ ( "text", RichTextBlock( label="Textový editor", features=ARTICLE_RICH_TEXT_FEATURES ), ) ], verbose_name="Článek", blank=True, use_json_field=True, ) tags = ClusterTaggableManager(through=Elections2021ArticleTag, blank=True) card_style = models.CharField( "styl karty článku", choices=STYLE_CHOICES, default=WHITE, max_length=10 ) ### PANELS content_panels = ArticleMixin.content_panels + [ FieldPanel("tags"), FieldPanel("card_style"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), HelpPanel( admin_help.build( admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX ) ), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [PublishingPanel(), CommentPanel()] ### RELATIONS parent_page_types = ["elections2021.Elections2021ArticlesPage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Aktualita" def card_css_class(self): return STYLE_CSS[self.card_style] def get_context(self, request): context = super().get_context(request) context["related_articles"] = ( self.get_siblings(inclusive=False) .live() .specific() .order_by("-elections2021articlepage__timestamp")[:3] ) return context class Elections2021ArticlesPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) ### PANELS content_panels = Page.content_panels + [FieldPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = ["elections2021.Elections2021ArticlePage"] ### OTHERS class Meta: verbose_name = "Aktuality" def get_meta_image(self): return self.search_image or self.photo def get_context(self, request): context = super().get_context(request) context["articles"] = Paginator( self.get_children() .live() .specific() .order_by("-elections2021articlepage__timestamp"), ARTICLES_PER_PAGE, ).get_page(request.GET.get("page")) return context class Elections2021CandidatesListPage( SubpageMixin, MetadataPageMixin, RoutablePageMixin, Page ): ### FIELDS photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) ### PANELS content_panels = Page.content_panels + [FieldPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = ["elections2021.Elections2021CandidatePage"] ### OTHERS class Meta: verbose_name = "Kandidáti" def get_meta_image(self): return self.search_image or self.photo def get_context(self, request): context = super().get_context(request) context["region_options"] = REGION_OPTIONS return context def get_region_list_url(self, slug=None): if slug is None: slug = list(REGION_SLUGS.keys())[0] return self.url + self.reverse_subpage("region_list", args=(slug,)) @route(r"^$") @route(r"^kraj/$") @route(r"^kraj/([a-z]+)/$") def region_list(self, request, param=None): region = param if param in REGION_SLUGS else None if not region: return HttpResponseRedirect(self.get_region_list_url()) candidates = ( self.get_children() .filter(elections2021candidatepage__region=REGION_SLUGS[region]) .live() .specific() .order_by("elections2021candidatepage__number") ) context = { "active_region": region, "candidates_top": candidates[:TOP_CANDIDATES_NUM], "candidates_bottom": candidates[TOP_CANDIDATES_NUM:], } return self.render(request, context_overrides=context) class Elections2021CandidatesMapPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) ### PANELS content_panels = Page.content_panels + [FieldPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Kandidáti mapa" def get_meta_image(self): return self.search_image or self.photo class Elections2021CandidatePage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS party = models.CharField( "strana", choices=PARTY_CHOICES, default=PIRATES, max_length=6 ) region = models.CharField("kraj", choices=REGION_CHOICES, max_length=3) number = models.IntegerField("pořadí") age = models.IntegerField("věk") occupation = models.CharField("povolání", max_length=255) city = models.CharField("bydliště", max_length=100) resume = RichTextField("medailonek", features=CANDIDATE_RICH_TEXT_FEATURES) email = models.EmailField("email", null=True, blank=True) phone = models.CharField("telefon", null=True, blank=True, max_length=20) facebook_url = models.URLField("Facebook URL", blank=True, null=True) twitter_url = models.URLField("Twitter URL", blank=True, null=True) instagram_url = models.URLField("Instagram URL", blank=True, null=True) website_url = models.URLField("webová stránka", blank=True, null=True) photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="foto", ) ### PANELS content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel("party", widget=forms.RadioSelect), FieldPanel("region"), FieldPanel("number"), ], "zařazení", ), MultiFieldPanel( [ FieldPanel("age"), FieldPanel("occupation"), FieldPanel("city"), ], "osobní údaje", ), FieldPanel("photo"), FieldPanel("resume"), MultiFieldPanel( [ FieldPanel("email"), FieldPanel("phone"), FieldPanel("facebook_url"), FieldPanel("twitter_url"), FieldPanel("instagram_url"), FieldPanel("website_url"), ], "kontakty", ), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021CandidatesListPage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Detail kandidáta" def get_meta_image(self): return self.photo def get_meta_description(self): name = REGION_NAME_VARIANT[self.region] return f"Kandidát č. {self.number} za koalici Piráti a Starostové v {name}." @property def party_name(self): return PARTY_NAME[self.party] @property def is_pirate(self): return self.party == PIRATES def get_region_list_url(self): slug = next(slug for slug, code in REGION_SLUGS.items() if code == self.region) candidates_list = Elections2021CandidatesListPage.objects.live().first() return candidates_list.get_region_list_url(slug) class Elections2021ProgramPage( SubpageMixin, MetadataPageMixin, RoutablePageMixin, Page ): ### FIELDS head_title = models.CharField( "nadpis do hlavičky stránky", blank=True, null=True, max_length=255 ) photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) plan_economics_text = RichTextField( "Moderní ekonomika", blank=True, null=True, features=RESTRICTED_FEATURES ) plan_digital_text = RichTextField( "Digitální revoluce", blank=True, null=True, features=RESTRICTED_FEATURES ) plan_corruption_text = RichTextField( "Razantní boj s korupcí", blank=True, null=True, features=RESTRICTED_FEATURES ) plan_climate_text = RichTextField( "Důraz na klima", blank=True, null=True, features=RESTRICTED_FEATURES ) plan_countryside_text = RichTextField( "Rovnocenné regiony", blank=True, null=True, features=RESTRICTED_FEATURES ) plan_management_text = RichTextField( "Profesionální stát", blank=True, null=True, features=RESTRICTED_FEATURES ) plan_safe_country_text = RichTextField( "Sebevědomá a bezpečná země", blank=True, null=True, features=RESTRICTED_FEATURES, ) plan_care_text = RichTextField( "Jistota péče a pomoci", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_childless_text = RichTextField( "bezdětní text", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_childless_author_1 = models.CharField( "bezdětní podpis 1", null=True, blank=True, max_length=150 ) archetype_childless_author_2 = models.CharField( "bezdětní podpis 2", null=True, blank=True, max_length=150 ) archetype_childless_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="bezdětní foto", related_name="+", ) archetype_parents_text = RichTextField( "rodiče text", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_parents_author_1 = models.CharField( "rodiče podpis 1", null=True, blank=True, max_length=150 ) archetype_parents_author_2 = models.CharField( "rodiče podpis 2", null=True, blank=True, max_length=150 ) archetype_parents_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="rodiče foto", related_name="+", ) archetype_mature_text = RichTextField( "zralí text", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_mature_author_1 = models.CharField( "zralí podpis 1", null=True, blank=True, max_length=150 ) archetype_mature_author_2 = models.CharField( "zralí podpis 2", null=True, blank=True, max_length=150 ) archetype_mature_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="zralí foto", related_name="+", ) archetype_seniors_text = RichTextField( "senioři text", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_seniors_author_1 = models.CharField( "senioři podpis 1", null=True, blank=True, max_length=150 ) archetype_seniors_author_2 = models.CharField( "senioři podpis 2", null=True, blank=True, max_length=150 ) archetype_seniors_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="senioři foto", related_name="+", ) archetype_working_seniors_text = RichTextField( "pracující senioři text", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_working_seniors_author_1 = models.CharField( "pracující senioři podpis 1", null=True, blank=True, max_length=150 ) archetype_working_seniors_author_2 = models.CharField( "pracující senioři podpis 2", null=True, blank=True, max_length=150 ) archetype_working_seniors_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="pracující senioři foto", related_name="+", ) archetype_students_text = RichTextField( "studenti text", blank=True, null=True, features=RESTRICTED_FEATURES ) archetype_students_author_1 = models.CharField( "studenti podpis 1", null=True, blank=True, max_length=150 ) archetype_students_author_2 = models.CharField( "studenti podpis 2", null=True, blank=True, max_length=150 ) archetype_students_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="studenti foto", related_name="+", ) ministry_transport_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="doprava foto", related_name="+", ) ministry_finances_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="finance foto", related_name="+", ) ministry_culture_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="kultura foto", related_name="+", ) ministry_defense_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="obrana foto", related_name="+", ) ministry_social_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="práce a sociální věci foto", related_name="+", ) ministry_countryside_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="místní rozvoj foto", related_name="+", ) ministry_business_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="průmysl a obchod foto", related_name="+", ) ministry_justice_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="spravedlnost foto", related_name="+", ) ministry_schools_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="školství, mládež a tělovýchova foto", related_name="+", ) ministry_interior_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="vnitro foto", related_name="+", ) ministry_foreign_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="zahraniční věci foto", related_name="+", ) ministry_health_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="zdravotnictví foto", related_name="+", ) ministry_agriculture_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="zemědělství foto", related_name="+", ) ministry_environment_photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="životní prostředí foto", related_name="+", ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("head_title"), FieldPanel("photo"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] plan_panels = [ FieldPanel("plan_economics_text"), FieldPanel("plan_digital_text"), FieldPanel("plan_corruption_text"), FieldPanel("plan_climate_text"), FieldPanel("plan_countryside_text"), FieldPanel("plan_management_text"), FieldPanel("plan_safe_country_text"), FieldPanel("plan_care_text"), ] archetype_panels = [ MultiFieldPanel( [ FieldPanel("archetype_childless_text"), FieldPanel("archetype_childless_author_1"), FieldPanel("archetype_childless_author_2"), FieldPanel("archetype_childless_photo"), ], "archetyp bezdětní", ), MultiFieldPanel( [ FieldPanel("archetype_parents_text"), FieldPanel("archetype_parents_author_1"), FieldPanel("archetype_parents_author_2"), FieldPanel("archetype_parents_photo"), ], "archetyp rodiče", ), MultiFieldPanel( [ FieldPanel("archetype_mature_text"), FieldPanel("archetype_mature_author_1"), FieldPanel("archetype_mature_author_2"), FieldPanel("archetype_mature_photo"), ], "archetyp zralí", ), MultiFieldPanel( [ FieldPanel("archetype_seniors_text"), FieldPanel("archetype_seniors_author_1"), FieldPanel("archetype_seniors_author_2"), FieldPanel("archetype_seniors_photo"), ], "archetyp senioři", ), MultiFieldPanel( [ FieldPanel("archetype_working_seniors_text"), FieldPanel("archetype_working_seniors_author_1"), FieldPanel("archetype_working_seniors_author_2"), FieldPanel("archetype_working_seniors_photo"), ], "archetyp pracující senioři", ), MultiFieldPanel( [ FieldPanel("archetype_students_text"), FieldPanel("archetype_students_author_1"), FieldPanel("archetype_students_author_2"), FieldPanel("archetype_students_photo"), ], "archetyp studenti", ), ] ministry_panels = [ FieldPanel("ministry_transport_photo"), FieldPanel("ministry_finances_photo"), FieldPanel("ministry_culture_photo"), # FieldPanel("ministry_defense_photo"), FieldPanel("ministry_social_photo"), FieldPanel("ministry_countryside_photo"), FieldPanel("ministry_business_photo"), FieldPanel("ministry_justice_photo"), FieldPanel("ministry_schools_photo"), FieldPanel("ministry_interior_photo"), FieldPanel("ministry_foreign_photo"), FieldPanel("ministry_health_photo"), FieldPanel("ministry_agriculture_photo"), FieldPanel("ministry_environment_photo"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading=gettext_lazy("Content")), ObjectList(promote_panels, heading=gettext_lazy("Promote")), ObjectList(plan_panels, heading="plány"), ObjectList(archetype_panels, heading="archetypy"), ObjectList(ministry_panels, heading="rezorty"), ] ) ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = ["elections2021.Elections2021ProgramPointPage"] ### OTHERS class Meta: verbose_name = "Program" def get_meta_image(self): return self.search_image or self.photo def get_context(self, request): context = super().get_context(request) context["plan_choices"] = PLAN_CHOICES context["ministry_choices"] = MINISTRY_CHOICES context["show_archetype_icon"] = True context["show_pagination"] = True context["active_my_program"] = False context["has_my_program"] = ( Elections2021ProgramAppPage.get_my_selection(request) is not None ) context["show_app_banner"] = not context["has_my_program"] return context @staticmethod def get_archetype_image(archetype): return f"elections2021/images/archetype/{archetype}.svg" def get_my_program_url(self): return self.url + self.reverse_subpage("my_program") def get_full_program_url(self): return self.url + self.reverse_subpage("full_program") @route(r"^$") def plan_all(self, request): query = request.GET.get("q", None) context = {"query": query, "show_app_banner": not query} if query: points = Elections2021ProgramPointPage.objects.search(query) else: points = ( Elections2021ProgramPointPage.objects.live() .specific() .order_by("-default_order") ) points = Paginator(points, PROGRAM_POINTS_PER_PAGE).get_page( request.GET.get("page") ) context["points"] = points return self.render(request, context_overrides=context) @route(r"^plan/([a-z-]+)/$") def plan_detail(self, request, param=None): plan = param if param in PLAN_OPTIONS else None if not plan: return HttpResponseRedirect(self.url) title = None head_text = "" head_image = "" if plan: title = next(title for key, title in PLAN_CHOICES if key == plan) head_image = self.get_archetype_image(PLAN_ARCHETYPES[plan]) if plan == PLAN_ECONOMICS: head_text = self.plan_economics_text weights = ["weight_plan_economics"] elif plan == PLAN_DIGITAL: head_text = self.plan_digital_text weights = ["weight_plan_digital"] elif plan == PLAN_CORRUPTION: head_text = self.plan_corruption_text weights = ["weight_plan_corruption"] elif plan == PLAN_CLIMATE: head_text = self.plan_climate_text weights = ["weight_plan_climate"] elif plan == PLAN_COUNTRYSIDE: head_text = self.plan_countryside_text weights = ["weight_plan_countryside"] elif plan == PLAN_MANAGEMENT: head_text = self.plan_management_text weights = ["weight_plan_management"] elif plan == PLAN_SAFE_COUNTRY: head_text = self.plan_safe_country_text weights = ["weight_plan_safe_country"] elif plan == PLAN_CARE: head_text = self.plan_care_text weights = ["weight_plan_care"] context = { "active_plan": plan, "title": title, "head_image": head_image, "head_text": head_text, "points": Elections2021ProgramPointPage.filter_by_weights(weights), "show_app_banner": False, "show_pagination": False, } return self.render(request, context_overrides=context) @route(r"^resort/([a-z-]+)/$") def ministry_detail(self, request, param=None): # obrana a zahraničí sloučeny a přesměrovává se na "nové" zahraničí se # změněnou adresou na "eu-zahranici-obrana" if param in ["obrana", "zahranicni-veci"]: url = self.url + self.reverse_subpage( "ministry_detail", args=(MINISTRY_FOREIGN,) ) return HttpResponseRedirect(url) ministry = param if param in MINISTRY_OPTIONS else None if not ministry: return HttpResponseRedirect(self.url) title = next(title for key, title in MINISTRY_CHOICES if key == ministry) if ministry == MINISTRY_TRANSPORT: weights = ["weight_ministry_transport"] head_photo = self.ministry_transport_photo elif ministry == MINISTRY_FINANCES: weights = ["weight_ministry_finances"] head_photo = self.ministry_finances_photo elif ministry == MINISTRY_CULTURE: weights = ["weight_ministry_culture"] head_photo = self.ministry_culture_photo elif ministry == MINISTRY_DEFENSE: weights = ["weight_ministry_defense"] head_photo = self.ministry_defense_photo elif ministry == MINISTRY_SOCIAL: weights = ["weight_ministry_social"] head_photo = self.ministry_social_photo elif ministry == MINISTRY_COUNTRYSIDE: weights = ["weight_ministry_countryside"] head_photo = self.ministry_countryside_photo elif ministry == MINISTRY_BUSINESS: weights = ["weight_ministry_business"] head_photo = self.ministry_business_photo elif ministry == MINISTRY_JUSTICE: weights = ["weight_ministry_justice"] head_photo = self.ministry_justice_photo elif ministry == MINISTRY_SCHOOLS: weights = ["weight_ministry_schools"] head_photo = self.ministry_schools_photo elif ministry == MINISTRY_INTERIOR: weights = ["weight_ministry_interior"] head_photo = self.ministry_interior_photo elif ministry == MINISTRY_FOREIGN: weights = ["weight_ministry_foreign"] head_photo = self.ministry_foreign_photo elif ministry == MINISTRY_HEALTH: weights = ["weight_ministry_health"] head_photo = self.ministry_health_photo elif ministry == MINISTRY_AGRICULTURE: weights = ["weight_ministry_agriculture"] head_photo = self.ministry_agriculture_photo elif ministry == MINISTRY_ENVIRONMENT: weights = ["weight_ministry_environment"] head_photo = self.ministry_environment_photo context = { "active_ministry": ministry, "title": title, "head_photo": head_photo, "points": Elections2021ProgramPointPage.filter_by_weights(weights), "show_archetype_icon": False, "show_app_banner": False, "show_pagination": False, } return self.render(request, context_overrides=context) @route(r"^muj-program/$") def my_program(self, request): selection = Elections2021ProgramAppPage.get_my_selection(request) if selection is None: response = HttpResponseRedirect(self.url) # očekávali jsme data z cookie, ale nepodařilo se je získat, tak pro # jistotu cookie smažeme kdyby náhodou existovala s poškozenými daty response.delete_cookie(settings.ELECTIONS2021_COOKIE_NAME) return response weights = [] archetype = get_archetype(selection) if archetype == CHILDLESS: weights.append("weight_childless") archetype_text = self.archetype_childless_text archetype_author_1 = self.archetype_childless_author_1 archetype_author_2 = self.archetype_childless_author_2 archetype_photo = self.archetype_childless_photo elif archetype == PARENTS: weights.append("weight_parents") archetype_text = self.archetype_parents_text archetype_author_1 = self.archetype_parents_author_1 archetype_author_2 = self.archetype_parents_author_2 archetype_photo = self.archetype_parents_photo elif archetype == MATURE: weights.append("weight_mature") archetype_text = self.archetype_mature_text archetype_author_1 = self.archetype_mature_author_1 archetype_author_2 = self.archetype_mature_author_2 archetype_photo = self.archetype_mature_photo elif archetype == STUDENTS: weights.append("weight_students") archetype_text = self.archetype_students_text archetype_author_1 = self.archetype_students_author_1 archetype_author_2 = self.archetype_students_author_2 archetype_photo = self.archetype_students_photo elif archetype == SENIORS: weights.append("weight_seniors") archetype_text = self.archetype_seniors_text archetype_author_1 = self.archetype_seniors_author_1 archetype_author_2 = self.archetype_seniors_author_2 archetype_photo = self.archetype_seniors_photo elif archetype == WORKING_SENIORS: weights.append("weight_working_seniors") archetype_text = self.archetype_working_seniors_text archetype_author_1 = self.archetype_working_seniors_author_1 archetype_author_2 = self.archetype_working_seniors_author_2 archetype_photo = self.archetype_working_seniors_photo if selection["occupation"] == OCCUPATION_BUSINESS: weights.append("weight_self_employed") if selection["wealth"] == WEALTH_BAD: weights.append("weight_socially_weak") if NATURE in selection["topics"]: weights.append("weight_nature") if SPORT in selection["topics"]: weights.append("weight_sport") if HEALTH in selection["topics"]: weights.append("weight_health") if CULTURE in selection["topics"]: weights.append("weight_culture") if TECHNOLOGY in selection["topics"]: weights.append("weight_technology") if COUNTRYSIDE in selection["topics"]: weights.append("weight_countryside") if HOUSING in selection["topics"]: weights.append("weight_housing") if EDUCATION in selection["topics"]: weights.append("weight_education") points = Elections2021ProgramPointPage.filter_by_weights(weights) points = Paginator(points, PROGRAM_POINTS_PER_PAGE).get_page( request.GET.get("page") ) context = { "title": "Program pro mě", "points": points, "show_app_banner": False, "active_my_program": True, "archetype_text": archetype_text, "archetype_author_1": archetype_author_1, "archetype_author_2": archetype_author_2, "archetype_photo": archetype_photo, } return self.render(request, context_overrides=context) @route(r"^kompletni/$") def full_program(self, request): benefits_titles = dict(BENEFITS_CHOICES) toc = [] body = [] for ministry, title in MINISTRY_CHOICES: sub_toc = [] points = [] weight = f"weight_ministry_{MINISTRY_CODES[ministry]}" for page in Elections2021ProgramPointPage.filter_by_weights([weight]): points.append(page) sub_toc.append({"anchor": page.slug, "title": page.title}) body.append({"anchor": ministry, "title": title, "points": points}) toc.append({"anchor": ministry, "title": title, "sub_toc": sub_toc}) context = {"body": body, "toc": toc, "benefits_titles": benefits_titles} return self.render( request, context_overrides=context, template="elections2021/elections2021_full_program_page.html", ) class QuestionBlock(blocks.StructBlock): question = blocks.CharBlock(label="otázka") answer = blocks.RichTextBlock(label="odpověď", features=STANDARD_FEATURES) class Meta: label = "otázka a odpověď" icon = "doc-full" template = "elections2021/_question_block.html" class MainBenefitBlock(blocks.StructBlock): variant = blocks.ChoiceBlock(BENEFITS_CHOICES, label="název") text = blocks.RichTextBlock(label="text", features=STANDARD_FEATURES) class Meta: label = "hlavní benefit" icon = "pick" template = "elections2021/_main_benefit_block.html" def get_context(self, value, parent_context=None): context = super().get_context(value, parent_context=parent_context) context["photo"] = f"elections2021/images/benefits/{value['variant']}.jpg" context["title"] = next( title for num, title in BENEFITS_CHOICES if num == value["variant"] ) return context class BenefitBlock(blocks.StructBlock): title = blocks.CharBlock(label="název") text = blocks.RichTextBlock(label="text", features=STANDARD_FEATURES) class Meta: label = "benefit" icon = "pick" template = "elections2021/_benefit_block.html" class Elections2021ProgramPointPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS annotation = RichTextField( "anotace", blank=True, null=True, features=RESTRICTED_FEATURES ) problem = RichTextField( "problém", blank=True, null=True, features=RESTRICTED_FEATURES ) context = RichTextField( "kontext problému", blank=True, null=True, features=RESTRICTED_FEATURES ) ideal = RichTextField("ideál", blank=True, null=True, features=RESTRICTED_FEATURES) proposal = RichTextField( "navrhovaná opatření", blank=True, null=True, features=EXTRA_FEATURES ) time_horizon_text = RichTextField( "časový horizont textově", blank=True, null=True, features=STANDARD_FEATURES ) time_horizon_number = models.IntegerField( "časový horizont číslo", blank=True, null=True ) time_horizon_unit = models.CharField( "časový horizont jednotka", max_length=20, blank=True, null=True ) already_done = RichTextField( "co jsme už udělali", blank=True, null=True, features=EXTRA_FEATURES ) sources = RichTextField("zdroje", blank=True, null=True, features=STANDARD_FEATURES) faq = StreamField( [("question", QuestionBlock())], verbose_name="FAQ", blank=True, use_json_field=True, ) related_points = StreamField( [ ( "point", blocks.PageChooserBlock( label="programový bod", page_type=["elections2021.Elections2021ProgramPointPage"], ), ) ], verbose_name="související body", blank=True, use_json_field=True, ) benefit_for_all = RichTextField( "benefit pro společnost", blank=True, null=True, features=RESTRICTED_FEATURES ) benefits_main = StreamField( [("benefit", MainBenefitBlock())], verbose_name="hlavní benefity", blank=True, use_json_field=True, ) benefits = StreamField( [("benefit", BenefitBlock())], verbose_name="ostatní benefity", blank=True, use_json_field=True, ) default_order = models.IntegerField("výchozí řazení", default=0) # target weights weight_childless = models.IntegerField("váha bezdětní", default=0) weight_parents = models.IntegerField("váha rodiče", default=0) weight_mature = models.IntegerField("váha zralí", default=0) weight_seniors = models.IntegerField("váha senioři", default=0) weight_working_seniors = models.IntegerField("váha pracující senioři", default=0) weight_students = models.IntegerField("váha studenti", default=0) weight_self_employed = models.IntegerField("váha OSVČ", default=0) weight_socially_weak = models.IntegerField("váha sociálně slabí", default=0) weight_nature = models.IntegerField("váha příroda", default=0) weight_sport = models.IntegerField("váha sport", default=0) weight_health = models.IntegerField("váha zdraví", default=0) weight_culture = models.IntegerField("váha kultura", default=0) weight_technology = models.IntegerField("váha technologie", default=0) weight_countryside = models.IntegerField("váha regiony", default=0) weight_housing = models.IntegerField("váha bydlení", default=0) weight_education = models.IntegerField("váha vzdělávání", default=0) weight_plan_economics = models.IntegerField("váha moderní ekonomika", default=0) weight_plan_digital = models.IntegerField("váha digitalizace státu", default=0) weight_plan_corruption = models.IntegerField( "váha protikorupční strategie", default=0 ) weight_plan_climate = models.IntegerField("váha plán klima", default=0) weight_plan_countryside = models.IntegerField("váha plán rozvoj regionů", default=0) weight_plan_management = models.IntegerField("váha plán řízení státu", default=0) weight_plan_safe_country = models.IntegerField( "váha plán sebevědomá země", default=0 ) weight_plan_care = models.IntegerField("váha plán jistota péče", default=0) weight_ministry_transport = models.IntegerField( "váha ministerstvo dopravy", default=0 ) weight_ministry_finances = models.IntegerField( "váha ministerstvo financí", default=0 ) weight_ministry_culture = models.IntegerField( "váha ministerstvo kultury", default=0 ) weight_ministry_defense = models.IntegerField("váha ministerstvo obrany", default=0) weight_ministry_social = models.IntegerField( "váha ministerstvo práce a sociálních věcí", default=0 ) weight_ministry_countryside = models.IntegerField( "váha ministerstvo pro místní rozvoj", default=0 ) weight_ministry_business = models.IntegerField( "váha ministerstvo průmyslu a obchodu", default=0 ) weight_ministry_justice = models.IntegerField( "váha ministerstvo spravedlnosti", default=0 ) weight_ministry_schools = models.IntegerField( "váha ministerstvo školství, mládeže a tělovýchovy", default=0 ) weight_ministry_interior = models.IntegerField( "váha ministerstvo vnitra", default=0 ) weight_ministry_foreign = models.IntegerField( "váha ministerstvo zahraničních věcí", default=0 ) weight_ministry_health = models.IntegerField( "váha ministerstvo zdravotnictví", default=0 ) weight_ministry_agriculture = models.IntegerField( "váha ministerstvo zemědělství", default=0 ) weight_ministry_environment = models.IntegerField( "váha ministerstvo životního prostředí", default=0 ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("annotation"), FieldPanel("problem"), FieldPanel("context"), FieldPanel("ideal"), FieldPanel("proposal"), MultiFieldPanel( [ FieldPanel("time_horizon_number"), FieldPanel("time_horizon_unit"), FieldPanel("time_horizon_text"), ], "časový horizont", ), FieldPanel("already_done"), FieldPanel("sources"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] faq_panels = [FieldPanel("faq")] related_panels = [FieldPanel("related_points")] benefits_panels = [ FieldPanel("benefit_for_all"), FieldPanel("benefits_main"), FieldPanel("benefits"), ] weights_panels = [ FieldPanel("default_order"), MultiFieldPanel( [ FieldPanel("weight_childless"), FieldPanel("weight_parents"), FieldPanel("weight_mature"), FieldPanel("weight_seniors"), FieldPanel("weight_working_seniors"), FieldPanel("weight_students"), ], "archetypy", ), MultiFieldPanel( [ FieldPanel("weight_self_employed"), FieldPanel("weight_socially_weak"), ], "doplňující", ), MultiFieldPanel( [ FieldPanel("weight_nature"), FieldPanel("weight_sport"), FieldPanel("weight_health"), FieldPanel("weight_culture"), FieldPanel("weight_technology"), FieldPanel("weight_countryside"), FieldPanel("weight_housing"), FieldPanel("weight_education"), ], "zájmy", ), MultiFieldPanel( [ FieldPanel("weight_plan_economics"), FieldPanel("weight_plan_digital"), FieldPanel("weight_plan_corruption"), FieldPanel("weight_plan_climate"), FieldPanel("weight_plan_countryside"), FieldPanel("weight_plan_management"), FieldPanel("weight_plan_safe_country"), FieldPanel("weight_plan_care"), ], "plány", ), MultiFieldPanel( [ FieldPanel("weight_ministry_transport"), FieldPanel("weight_ministry_finances"), FieldPanel("weight_ministry_culture"), # FieldPanel("weight_ministry_defense"), FieldPanel("weight_ministry_social"), FieldPanel("weight_ministry_countryside"), FieldPanel("weight_ministry_business"), FieldPanel("weight_ministry_justice"), FieldPanel("weight_ministry_schools"), FieldPanel("weight_ministry_interior"), FieldPanel("weight_ministry_foreign"), FieldPanel("weight_ministry_health"), FieldPanel("weight_ministry_agriculture"), FieldPanel("weight_ministry_environment"), ], "ministerstva", ), ] import_panels = [ MultiFieldPanel( [ FieldPanel("import_file"), HelpPanel( 'Soubor z Goodle Docs stáhněte jako "Webová stránka (komprimovaný ' ' HTML soubor)" a ten nahrajte do formuláře.' ), ], "import programového bodu", ), ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading=gettext_lazy("Content")), ObjectList(promote_panels, heading=gettext_lazy("Promote")), ObjectList(faq_panels, heading="FAQ"), ObjectList(benefits_panels, heading="benefity"), ObjectList(related_panels, heading="související"), ObjectList(weights_panels, heading="váhy"), ObjectList(import_panels, heading="import"), ] ) ### RELATIONS parent_page_types = ["elections2021.Elections2021ProgramPage"] subpage_types = [] ### SEARCH search_fields = Page.search_fields + [ index.SearchField("annotation", boost=1.6), index.SearchField("problem"), index.SearchField("context"), index.SearchField("ideal"), index.SearchField("proposal"), ] ### OTHERS base_form_class = ProgramPointPageForm class Meta: verbose_name = "Programový bod" def get_meta_description(self): if self.search_description: return self.search_description return re.sub(r"<.*?>|\[.*?\]", "", self.annotation) @property def archetype(self): if self.weight_ministry_transport: return MINISTRY_ARCHETYPES[MINISTRY_TRANSPORT] if self.weight_ministry_finances: return MINISTRY_ARCHETYPES[MINISTRY_FINANCES] if self.weight_ministry_culture: return MINISTRY_ARCHETYPES[MINISTRY_CULTURE] if self.weight_ministry_defense: return MINISTRY_ARCHETYPES[MINISTRY_DEFENSE] if self.weight_ministry_social: return MINISTRY_ARCHETYPES[MINISTRY_SOCIAL] if self.weight_ministry_countryside: return MINISTRY_ARCHETYPES[MINISTRY_COUNTRYSIDE] if self.weight_ministry_business: return MINISTRY_ARCHETYPES[MINISTRY_BUSINESS] if self.weight_ministry_justice: return MINISTRY_ARCHETYPES[MINISTRY_JUSTICE] if self.weight_ministry_schools: return MINISTRY_ARCHETYPES[MINISTRY_SCHOOLS] if self.weight_ministry_interior: return MINISTRY_ARCHETYPES[MINISTRY_INTERIOR] if self.weight_ministry_foreign: return MINISTRY_ARCHETYPES[MINISTRY_FOREIGN] if self.weight_ministry_health: return MINISTRY_ARCHETYPES[MINISTRY_HEALTH] if self.weight_ministry_agriculture: return MINISTRY_ARCHETYPES[MINISTRY_AGRICULTURE] if self.weight_ministry_environment: return MINISTRY_ARCHETYPES[MINISTRY_ENVIRONMENT] return "" @classmethod def filter_by_weights(cls, weights): points = cls.objects.live().specific() if len(weights) > 1: return ( points.annotate(max_weight=Greatest(*weights)) .filter(max_weight__gt=0) .order_by("-max_weight") ) else: condition = {f"{weights[0]}__gt": 0} order = f"-{weights[0]}" return points.filter(**condition).order_by(order) class RichQuestionBlock(blocks.StructBlock): question = blocks.CharBlock(label="otázka") answer = blocks.RichTextBlock(label="odpověď", features=ARTICLE_RICH_TEXT_FEATURES) class Meta: label = "otázka a odpověď" icon = "doc-full" template = "elections2021/_rich_question_block.html" class Elections2021QuestionsPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS intro = RichTextField( "úvodní text", blank=True, features=ARTICLE_RICH_TEXT_FEATURES ) photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) myths = StreamField( [("question", RichQuestionBlock())], verbose_name="mýty o koalici", blank=True, use_json_field=True, ) elections = StreamField( [("question", RichQuestionBlock())], verbose_name="otázky k volbám", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("intro"), FieldPanel("photo"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] myths_panels = [FieldPanel("myths")] elections_panels = [FieldPanel("elections")] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading=gettext_lazy("Content")), ObjectList(myths_panels, heading="mýty"), ObjectList(elections_panels, heading="volby"), ObjectList(promote_panels, heading=gettext_lazy("Promote")), ] ) ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "FAQ" def get_meta_image(self): return self.search_image or self.photo class Elections2021ProgramAppPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS info_title = models.CharField( "titulek k informacím", blank=True, null=True, max_length=255 ) info_text = RichTextField( "základní informace", blank=True, null=True, features=RESTRICTED_FEATURES ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("info_title"), FieldPanel("info_text"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Programová aplikace" def serve(self, request, *args, **kwargs): if request.method == "POST": form = ProgramAppForm(request.POST) if form.is_valid(): program_page = Elections2021ProgramPage.objects.live().first() response = HttpResponseRedirect(program_page.get_my_program_url()) response.set_signed_cookie( settings.ELECTIONS2021_COOKIE_NAME, json.dumps(form.cleaned_data), secure=settings.SESSION_COOKIE_SECURE, httponly=settings.SESSION_COOKIE_HTTPONLY, ) return response return super().serve(request, *args, **kwargs) @staticmethod def get_my_selection(request): data = request.get_signed_cookie(settings.ELECTIONS2021_COOKIE_NAME, None) if data: try: return json.loads(data) except json.JSONDecodeError: pass return None def get_context(self, request): context = super().get_context(request) selection = self.get_my_selection(request) if selection is None: selection = { "age": AGE_30_49, "kids": True, "wealth": WEALTH_AVERAGE, "occupation": OCCUPATION_WORKING, "topics": [], } context["active"] = { "age": selection["age"], "kids": selection["kids"], "wealth": selection["wealth"], "occupation": selection["occupation"], "nature": NATURE in selection["topics"], "sport": SPORT in selection["topics"], "health": HEALTH in selection["topics"], "culture": CULTURE in selection["topics"], "technology": TECHNOLOGY in selection["topics"], "countryside": COUNTRYSIDE in selection["topics"], "housing": HOUSING in selection["topics"], "education": EDUCATION in selection["topics"], } return context class Elections2021TextPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS body = RichTextField( "obsah stránky", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) ### 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(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Textová stránka" class Elections2021StrategicListPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS ### PANELS promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = ["elections2021.Elections2021StrategicPage"] ### OTHERS class Meta: verbose_name = "Strategické dokumenty" def get_context(self, request): context = super().get_context(request) context["strategic_documents"] = Paginator( self.get_children().live().specific(), STRATEGIC_PER_PAGE ).get_page(request.GET.get("page")) return context class Elections2021StrategicPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS card_style = models.CharField( "styl karty v přehledu", choices=STYLE_CHOICES, default=WHITE, max_length=10 ) perex = models.TextField("perex") content = StreamField( [ ( "title", blocks.CharBlock( label="nadpis sekce (pro navigaci)", icon="title", template="elections2021/_strategic_title_block.html", ), ), ( "text", blocks.RichTextBlock( label="text", features=STRATEGIC_RICH_TEXT_FEATURES, template="elections2021/_strategic_text_block.html", ), ), ], verbose_name="obsah stránky", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("perex"), FieldPanel("content"), FieldPanel("card_style"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [PublishingPanel(), CommentPanel()] ### RELATIONS parent_page_types = ["elections2021.Elections2021StrategicListPage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Strategický dokument" def get_context(self, request): context = super().get_context(request) context["navigation"] = [] for block in self.content: if block.block_type == "title": context["navigation"].append((slugify(block.value), block.value)) return context class Elections2021MythsPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS ### PANELS promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = ["elections2021.Elections2021MythPage"] ### OTHERS class Meta: verbose_name = "Nejčastější mýty" def get_context(self, request): context = super().get_context(request) context["myths"] = self.get_children().live().specific() return context class Elections2021MythPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS perex = models.TextField("perex") myth = RichTextField( "co se říká?", blank=True, null=True, features=STRATEGIC_RICH_TEXT_FEATURES ) reality = RichTextField( "co ve skutečnosti prosazujeme", blank=True, null=True, features=STRATEGIC_RICH_TEXT_FEATURES, ) related_points = StreamField( [ ( "point", blocks.PageChooserBlock( label="programový bod", page_type=["elections2021.Elections2021ProgramPointPage"], ), ) ], verbose_name="související programové body", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("perex"), FieldPanel("myth"), FieldPanel("reality"), FieldPanel("related_points"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), HelpPanel( admin_help.build( admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX ) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021MythsPage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Mýtus" 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 DownloadDocumentBlock(blocks.StructBlock): title = blocks.CharBlock(label="název") photo = ImageChooserBlock(label="náhled") document = DocumentChooserBlock(label="dokument") class Meta: label = "dokument ke stažení" icon = "doc-full" template = "elections2021/_download_document_block.html" def get_context(self, value, parent_context=None): context = super().get_context(value, parent_context=parent_context) ext = value["document"].url.lower().split(".")[-1] context["icon"] = f"elections2021/images/pretty-file-icons/svg/{ext}.svg" return context class DownloadSpotifyBlock(blocks.StructBlock): title = blocks.CharBlock(label="název") photo = ImageChooserBlock(label="náhled") url = blocks.URLBlock(label="odkaz na Spotify") class Meta: label = "odkaz na Spotify" icon = "media" template = "elections2021/_download_spotify_block.html" class DownloadTextDocumentBlock(blocks.StructBlock): title = blocks.CharBlock(label="název") document = DocumentChooserBlock(label="dokument") class Meta: label = "dokument ke stažení" icon = "doc-full" class Elections2021DownloadsPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS downloads = StreamField( [("document", DownloadDocumentBlock()), ("spotify", DownloadSpotifyBlock())], verbose_name="soubory ke stažení", blank=True, use_json_field=True, ) text_downloads = StreamField( [("document", DownloadTextDocumentBlock())], verbose_name="textové soubory ke stažení", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("downloads"), FieldPanel("text_downloads"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Soubory ke stažení" class GovernmentTeamMemberBlock(blocks.StructBlock): name = blocks.CharBlock(label="jméno") photo = ImageChooserBlock(label="fotka") occupation = blocks.CharBlock(label="povolání") resume = blocks.TextBlock(label="medailonek") class Meta: label = "člen vládního týmu" icon = "user" template = "elections2021/_government_team_member_block.html" class GovernmentSectionBlock(blocks.StructBlock): title = blocks.CharBlock(label="název") members = blocks.ListBlock(GovernmentTeamMemberBlock()) class Meta: label = "sekce vládního týmu" icon = "group" template = "elections2021/_government_section_block.html" class Elections2021GovernmentTeamPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) sections = StreamField( [("section", GovernmentSectionBlock())], verbose_name="sekce vládního týmu", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("photo"), FieldPanel("sections"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Vládní tým" def get_meta_image(self): return self.search_image or self.photo class Elections2021CalendarPage(SubpageMixin, MetadataPageMixin, CalendarMixin, Page): ### FIELDS photo = models.ForeignKey( "wagtailimages.Image", on_delete=models.PROTECT, blank=True, null=True, verbose_name="hlavní fotka", ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("photo"), FieldPanel("calendar_url"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Kalendář" def get_meta_image(self): return self.search_image or self.photo @property def has_calendar(self): return self.calendar_id is not None def get_calendar(self): for event in self.calendar.future_events: event["pir"] = {"name": None, "tags": [], "region": None} pir_name = [] for word in event.get("name", "").split(): if word.startswith("#"): event["pir"]["tags"].append(word[1:]) else: pir_name.append(word) if len(pir_name) > 0: if pir_name[0].endswith(":") and len(pir_name[0]) == 4: event["pir"]["region"] = pir_name.pop(0)[:-1] event["pir"]["name"] = " ".join(pir_name) return self.calendar class Token(models.Model): scope = models.CharField(max_length=127) bearer = models.CharField(max_length=40) comment = models.CharField(max_length=255) class BannerBlock(blocks.StructBlock): code = blocks.CharBlock(label="kód banneru") candidate1 = blocks.CharBlock(label="první kandidát", required=False) candidate2 = blocks.CharBlock(label="druhý kandidát", required=False) tagline = blocks.CharBlock(label="slogan", required=False) preview = ImageChooserBlock(label="náhled") class Meta: label = "plachta" icon = "flag" template = "elections2021/_banner_block.html" class BannerOrder(models.Model): code = models.CharField(max_length=10) name = models.CharField(max_length=35) surname = models.CharField(max_length=70) residency = models.CharField(max_length=70) date_of_birth = models.DateField() phone = models.CharField(max_length=20) email = models.EmailField(max_length=70) note = models.CharField(max_length=255, blank=True) class BannerForm(forms.ModelForm): class Meta: model = BannerOrder fields = [ "code", "name", "surname", "residency", "date_of_birth", "phone", "email", "note", ] class Elections2021BannerListPage( SubpageMixin, MetadataPageMixin, RoutablePageMixin, Page ): ### FIELDS subtitle = models.CharField(max_length=100, blank=True, verbose_name="podtitulek") banners = StreamField( [("banners", BannerBlock())], verbose_name="objednávání plachet", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("subtitle"), FieldPanel("banners"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021MapPage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "nabídka plachet" def serve(self, request, *args, **kwargs): if request.method == "POST": form = BannerForm(request.POST) form.has_been_saved = False if form.is_valid(): form.save() form.has_been_saved = True else: form = BannerForm() form.has_been_saved = False request.banner_form = form return super().serve(request, *args, **kwargs) class Elections2021MapPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS subtitle = models.CharField(max_length=100, blank=True, verbose_name="podtitulek") praha = models.ForeignKey( "wagtailcore.Page", verbose_name="Praha", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) stredocesky = models.ForeignKey( "wagtailcore.Page", verbose_name="Středočeský", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) jihocesky = models.ForeignKey( "wagtailcore.Page", verbose_name="Jihočeský", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) plzensky = models.ForeignKey( "wagtailcore.Page", verbose_name="Plzeňský", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) karlovarsky = models.ForeignKey( "wagtailcore.Page", verbose_name="Karlovarský", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) ustecky = models.ForeignKey( "wagtailcore.Page", verbose_name="Ústecký", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) liberecky = models.ForeignKey( "wagtailcore.Page", verbose_name="Liberecký", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) kralovehradecky = models.ForeignKey( "wagtailcore.Page", verbose_name="Královéhradecký", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) moravskoslezsky = models.ForeignKey( "wagtailcore.Page", verbose_name="Moravskoslezský", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) pardubicky = models.ForeignKey( "wagtailcore.Page", verbose_name="Pardubický", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) vysocina = models.ForeignKey( "wagtailcore.Page", verbose_name="Vysočina", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) jihomoravsky = models.ForeignKey( "wagtailcore.Page", verbose_name="Jihomoravsý", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) olomoucky = models.ForeignKey( "wagtailcore.Page", verbose_name="Olomoucký", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) zlinsky = models.ForeignKey( "wagtailcore.Page", verbose_name="Zlínský", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("subtitle"), MultiFieldPanel( [ PageChooserPanel("praha", "wagtailcore.Page"), PageChooserPanel("stredocesky", "wagtailcore.Page"), PageChooserPanel("jihocesky", "wagtailcore.Page"), PageChooserPanel("plzensky", "wagtailcore.Page"), PageChooserPanel("karlovarsky", "wagtailcore.Page"), PageChooserPanel("ustecky", "wagtailcore.Page"), PageChooserPanel("liberecky", "wagtailcore.Page"), PageChooserPanel("kralovehradecky", "wagtailcore.Page"), PageChooserPanel("moravskoslezsky", "wagtailcore.Page"), PageChooserPanel("pardubicky", "wagtailcore.Page"), PageChooserPanel("vysocina", "wagtailcore.Page"), PageChooserPanel("jihomoravsky", "wagtailcore.Page"), PageChooserPanel("olomoucky", "wagtailcore.Page"), PageChooserPanel("zlinsky", "wagtailcore.Page"), ], "Rozcestník krajů", ), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel( admin_help.build(admin_help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO) ), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = ["elections2021.Elections2021BannerListPage"] ### OTHERS class Meta: verbose_name = "mapa krajů" class NutshellItemBlock(blocks.StructBlock): text = blocks.TextBlock(label="text") points = blocks.ListBlock( blocks.StructBlock( [ ("title", blocks.TextBlock(label="titulek")), ( "point", blocks.PageChooserBlock( label="programový bod", page_type=["elections2021.Elections2021ProgramPointPage"], ), ), ] ), label="programové body", ) class Meta: label = "blok programu v kostce" template = "elections2021/_nutshell_item_block.html" class NutshellSectionBlock(blocks.StructBlock): title = blocks.CharBlock(label="nadpis") items = blocks.ListBlock(NutshellItemBlock(), label="bloky") class Meta: label = "sekce programu v kostce" template = "elections2021/_nutshell_section_block.html" class Elections2021ProgramInNutshellPage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS leading = models.TextField("úvod", blank=True, null=True) subtitle = models.CharField("podnadpis", blank=True, null=True, max_length=255) body = RichTextField( "obsah", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) content = StreamField( [("section", NutshellSectionBlock())], verbose_name="sekce", blank=True, use_json_field=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("leading"), FieldPanel("subtitle"), FieldPanel("body"), FieldPanel("content"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Program v kostce" class Elections2021GoingToVotePage(SubpageMixin, MetadataPageMixin, Page): ### FIELDS subtitle = models.CharField("podnadpis", blank=True, null=True, max_length=255) header_text = RichTextField( "text v hlavičce", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) video = models.URLField("video na youtube", blank=True, null=True) bottom_title = models.CharField( "spodní nadpis", blank=True, null=True, max_length=255 ) bottom_text = RichTextField( "spodní obsah", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section1_title = models.CharField("titulek", blank=True, null=True, max_length=255) section1_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section1_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section2_title = models.CharField("titulek", blank=True, null=True, max_length=255) section2_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section2_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section3_title = models.CharField("titulek", blank=True, null=True, max_length=255) section3_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section3_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section4_title = models.CharField("titulek", blank=True, null=True, max_length=255) section4_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section4_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section6_title = models.CharField("titulek", blank=True, null=True, max_length=255) section6_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section6_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section7_title = models.CharField("titulek", blank=True, null=True, max_length=255) section7_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section7_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section8_title = models.CharField("titulek", blank=True, null=True, max_length=255) section8_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section8_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) section9_title = models.CharField("titulek", blank=True, null=True, max_length=255) section9_text = RichTextField( "program", blank=True, null=True, features=ARTICLE_RICH_TEXT_FEATURES ) section9_image = models.ForeignKey( "wagtailimages.Image", verbose_name="obrázek", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("subtitle"), FieldPanel("header_text"), FieldPanel("video"), MultiFieldPanel( [FieldPanel("bottom_title"), FieldPanel("bottom_text")], "spodní obsah" ), MultiFieldPanel( [ FieldPanel("section1_title"), FieldPanel("section1_text"), FieldPanel("section1_image"), ], "sekce 1", ), MultiFieldPanel( [ FieldPanel("section2_title"), FieldPanel("section2_text"), FieldPanel("section2_image"), ], "sekce 2", ), MultiFieldPanel( [ FieldPanel("section3_title"), FieldPanel("section3_text"), FieldPanel("section3_image"), ], "sekce 3", ), MultiFieldPanel( [ FieldPanel("section4_title"), FieldPanel("section4_text"), FieldPanel("section4_image"), ], "sekce 4", ), MultiFieldPanel( [ FieldPanel("section6_title"), FieldPanel("section6_text"), FieldPanel("section6_image"), ], "sekce 6", ), MultiFieldPanel( [ FieldPanel("section7_title"), FieldPanel("section7_text"), FieldPanel("section7_image"), ], "sekce 7", ), MultiFieldPanel( [ FieldPanel("section8_title"), FieldPanel("section8_text"), FieldPanel("section8_image"), ], "sekce 8", ), MultiFieldPanel( [ FieldPanel("section9_title"), FieldPanel("section9_text"), FieldPanel("section9_image"), ], "sekce 9", ), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), FieldPanel("search_image"), HelpPanel(admin_help.build(admin_help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] settings_panels = [] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Jdeme k volbám"