import json 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.translation import gettext_lazy from modelcluster.contrib.taggit import ClusterTaggableManager from modelcluster.fields import ParentalKey from taggit.models import TaggedItemBase from wagtail.admin.edit_handlers import ( CommentPanel, FieldPanel, HelpPanel, MultiFieldPanel, ObjectList, PublishingPanel, StreamFieldPanel, TabbedInterface, ) from wagtail.contrib.routable_page.models import RoutablePageMixin, route from wagtail.core import blocks from wagtail.core.fields import RichTextField, StreamField from wagtail.core.models import Page from wagtail.images.edit_handlers import ImageChooserPanel from wagtailmetadata.models import MetadataPageMixin from shared.models import ArticleMixin, SubpageMixin from shared.utils import get_subpage_url from tuning import help from .constants import ( 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_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, 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, STUDENTS, STYLE_CHOICES, STYLE_CSS, TECHNOLOGY, TOP_CANDIDATES_NUM, 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 Elections2021HomePage(Page, MetadataPageMixin): ### FIELDS header_links = StreamField( [("link", LinkBlock())], verbose_name="odkazy v záhlaví", blank=True ) footer_links = StreamField( [("link", LinkBlock())], verbose_name="odkazy v zápatí", blank=True ) matomo_id = models.IntegerField( "Matomo ID pro sledování návštěvnosti", blank=True, null=True ) ### PANELS promote_panels = [ MultiFieldPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.IMPORTANT_TITLE)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [ FieldPanel("matomo_id"), StreamFieldPanel("header_links"), StreamFieldPanel("footer_links"), CommentPanel(), ] ### RELATIONS subpage_types = [ "elections2021.Elections2021ArticlesPage", "elections2021.Elections2021CandidatesListPage", "elections2021.Elections2021CandidatesMapPage", "elections2021.Elections2021ProgramPage", "elections2021.Elections2021QuestionsPage", "elections2021.Elections2021ProgramAppPage", ] ### 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) class Elections2021ArticleTag(TaggedItemBase): content_object = ParentalKey( "elections2021.Elections2021ArticlePage", on_delete=models.CASCADE ) class Elections2021ArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page): ### FIELDS text = RichTextField("článek", blank=True, features=ARTICLE_RICH_TEXT_FEATURES) 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(help.build(help.NO_SEO_TITLE, 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 get_meta_image(self): return self.image 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 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__date")[: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 + [ImageChooserPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [CommentPanel()] ### 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__date"), 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 + [ImageChooserPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [CommentPanel()] ### 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 + [ImageChooserPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [CommentPanel()] ### 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", ), ImageChooserPanel("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"), ), ] settings_panels = [CommentPanel()] ### 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 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 ) ### PANELS content_panels = Page.content_panels + [ImageChooserPanel("photo")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(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"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading=gettext_lazy("Content")), ObjectList(promote_panels, heading=gettext_lazy("Promote")), ObjectList(plan_panels, heading="plány"), ] ) ### 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, parent_context=None): context = super().get_context(request, parent_context=parent_context) context["plan_choices"] = PLAN_CHOICES context["ministry_choices"] = MINISTRY_CHOICES context["show_archetype_icon"] = True context["show_app_banner"] = True context["show_pagination"] = True context["active_my_program"] = False context["has_my_program"] = self.get_my_selection(request) is not None 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_my_selection(self, request): data = request.get_signed_cookie(settings.ELECTIONS2021_COOKIE_NAME, None) if data: try: return json.loads(data) except json.JSONDecodeError: pass return None @route(r"^$") def plan_all(self, request, param=None): points = Elections2021ProgramPointPage.objects.live().specific() 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 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): ministry = param if param in MINISTRY_OPTIONS else None title = None head_text = "" head_image = "" if ministry: title = next(title for key, title in MINISTRY_CHOICES if key == ministry) head_image = self.get_archetype_image(MINISTRY_ARCHETYPES[ministry]) if ministry == MINISTRY_TRANSPORT: weights = ["weight_ministry_transport"] elif ministry == MINISTRY_FINANCES: weights = ["weight_ministry_finances"] elif ministry == MINISTRY_CULTURE: weights = ["weight_ministry_culture"] elif ministry == MINISTRY_DEFENSE: weights = ["weight_ministry_defense"] elif ministry == MINISTRY_SOCIAL: weights = ["weight_ministry_social"] elif ministry == MINISTRY_COUNTRYSIDE: weights = ["weight_ministry_countryside"] elif ministry == MINISTRY_BUSINESS: weights = ["weight_ministry_business"] elif ministry == MINISTRY_JUSTICE: weights = ["weight_ministry_justice"] elif ministry == MINISTRY_SCHOOLS: weights = ["weight_ministry_schools"] elif ministry == MINISTRY_INTERIOR: weights = ["weight_ministry_interior"] elif ministry == MINISTRY_FOREIGN: weights = ["weight_ministry_foreign"] elif ministry == MINISTRY_HEALTH: weights = ["weight_ministry_health"] elif ministry == MINISTRY_AGRICULTURE: weights = ["weight_ministry_agriculture"] elif ministry == MINISTRY_ENVIRONMENT: weights = ["weight_ministry_environment"] context = { "active_ministry": ministry, "title": title, "head_image": head_image, "head_text": head_text, "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 = self.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") elif archetype == PARENTS: weights.append("weight_parents") elif archetype == MATURE: weights.append("weight_mature") elif archetype == STUDENTS: weights.append("weight_students") elif archetype == SENIORS: weights.append("weight_seniors") elif archetype == WORKING_SENIORS: weights.append("weight_working_seniors") 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, } return self.render(request, context_overrides=context) 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, ) related_points = StreamField( [ ( "point", blocks.PageChooserBlock( label="programový bod", page_type=["elections2021.Elections2021ProgramPointPage"], ), ) ], verbose_name="související body", blank=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, ) benefits = StreamField( [("benefit", BenefitBlock())], verbose_name="ostatní benefity", blank=True, ) # 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"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] faq_panels = [StreamFieldPanel("faq")] related_panels = [StreamFieldPanel("related_points")] benefits_panels = [ FieldPanel("benefit_for_all"), StreamFieldPanel("benefits_main"), StreamFieldPanel("benefits"), ] weights_panels = [ 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 = [] ### OTHERS base_form_class = ProgramPointPageForm class Meta: verbose_name = "Programový bod" @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, ) elections = StreamField( [("question", RichQuestionBlock())], verbose_name="otázky k volbám", blank=True, ) ### PANELS content_panels = Page.content_panels + [ FieldPanel("intro"), ImageChooserPanel("photo"), ] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)), ], gettext_lazy("Common page configuration"), ), CommentPanel(), ] myths_panels = [StreamFieldPanel("myths")] elections_panels = [StreamFieldPanel("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_text = RichTextField( "základní informace", blank=True, null=True, features=RESTRICTED_FEATURES ) ### PANELS content_panels = Page.content_panels + [FieldPanel("info_text")] promote_panels = [ MultiFieldPanel( [ FieldPanel("slug"), FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("search_image"), HelpPanel(help.build(help.NO_SEO_TITLE)), ], gettext_lazy("Common page configuration"), ), ] settings_panels = [CommentPanel()] ### RELATIONS parent_page_types = ["elections2021.Elections2021HomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Programová aplikace" def serve(self, request): 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)