from datetime import timedelta from functools import cached_property from django.conf import settings from django.db import models from django.http import HttpResponseRedirect from django.shortcuts import render from django.utils import timezone from modelcluster.contrib.taggit import ClusterTaggableManager from modelcluster.fields import ParentalKey from taggit.models import TaggedItemBase from wagtail.admin.edit_handlers import ( FieldPanel, HelpPanel, MultiFieldPanel, ObjectList, TabbedInterface, ) from wagtail.contrib.routable_page.models import route from wagtail.core.blocks import CharBlock, PageChooserBlock, RichTextBlock from wagtail.core.fields import RichTextField, StreamField from wagtail.core.models import Page from wagtailmetadata.models import MetadataPageMixin from elections2021.constants import REGION_CHOICES # pozor, import ze sousedního modulu from shared.const import RICH_TEXT_DEFAULT_FEATURES from shared.forms import SubscribeForm from shared.models import ( # MenuMixin, ArticleMixin, ExtendedMetadataHomePageMixin, ExtendedMetadataPageMixin, SubpageMixin, ) from shared.utils import make_promote_panels, subscribe_to_newsletter from tuning import admin_help from twitter_utils.models import Tweet from . import blocks from .forms import JekyllImportForm from .menu import MenuMixin class ARTICLE_TYPES(models.IntegerChoices): WORK_TIMELINE = 1, "Článek na timeline Piráti pracují" PRESS_RELEASE = 2, "Tisková zpráva" class MainHomePage(MenuMixin, ExtendedMetadataHomePageMixin, MetadataPageMixin, Page): # header contact_newcomers = models.URLField( "URL pro zájemce o členství", blank=True, null=True, default="https://nalodeni.pirati.cz", ) donation_page = models.URLField( "URL pro příjem darů (tlačítko Dary)", blank=True, null=True, default="https://dary.pirati.cz", ) # content content = StreamField( [ ("carousel", blocks.HomePageCarouselBlock()), ("news", blocks.NewsBlock()), ("people", blocks.PeopleOverviewBlock()), ("regions", blocks.RegionsBlock()), ("tweets", blocks.TweetsBlock()), ("boxes", blocks.BoxesBlock()), ], verbose_name="Hlavní obsah", blank=True, ) # footer footer_other_links = StreamField( [ ("other_links", blocks.OtherLinksBlock()), ], verbose_name="Bloky dalších odkazů v zápatí webu", blank=True, ) footer_person_list = StreamField( [("person", blocks.PersonContactBlock())], verbose_name="Osoby v zápatí webu", blank=True, max_num=6, ) # settings matomo_id = models.IntegerField( "Matomo ID pro sledování návštěvnosti", blank=True, null=True ) social_links = StreamField( [ ("social_links", blocks.SocialLinkBlock()), ], verbose_name="Odkazy na sociální sítě v zápatí webu", blank=True, ) twitter_usernames = StreamField( [("username", CharBlock(label="Twitter uživatelské jméno"))], verbose_name="Uživatelská jména pro synchronizované twitter účty", blank=True, max_num=6, ) content_panels = Page.content_panels + [ FieldPanel("content"), FieldPanel("footer_other_links"), FieldPanel("footer_person_list"), ] settings_panels = [ FieldPanel("contact_newcomers"), FieldPanel("donation_page"), FieldPanel("social_links"), FieldPanel("matomo_id"), FieldPanel("twitter_usernames"), ] ### EDIT HANDLERS edit_handler = TabbedInterface( [ ObjectList(content_panels, heading="Obsah"), ObjectList(settings_panels, heading="Nastavení"), ObjectList(MenuMixin.menu_panels, heading="Menu"), ] ) ### RELATIONS subpage_types = [ "main.MainArticlesPage", "main.MainProgramPage", "main.MainPeoplePage", "main.MainPersonPage", "main.MainContactPage", ] ### OTHERS class Meta: verbose_name = "HomePage pirati.cz" @staticmethod def get_404_response(request): return render(request, "main/404.html", status=404) def get_context(self, request, *args, **kwargs): context = super().get_context(request, args, kwargs) context["tweet_list"] = Tweet.objects.order_by("-twitter_id")[:4] return context @cached_property def newsletter_subscribe_url(self): return self.url + self.reverse_subpage("newsletter_subscribe") @property def root_page(self): return self @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.PIRATICZ_NEWSLETTER_ID, settings.PIRATICZ_NEWSLETTER_SOURCE, ) 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 MainArticlesPage( ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page ): perex = models.TextField() timeline = StreamField( # TODO delete [ ( "article_list", PageChooserBlock( page_type="main.MainArticlePage", label="Vybrat aktualitu" ), ) ], verbose_name="Timeline", blank=True, ) last_import_log = models.TextField( "Výstup z posledního importu", null=True, blank=True ) import_panels = [ MultiFieldPanel( [ FieldPanel("do_import"), FieldPanel("collection"), FieldPanel("dry_run"), FieldPanel("jekyll_repo_url"), FieldPanel("readonly_log"), HelpPanel( "Import provádějte vždy až po vytvoření stránky aktualit. " 'Pro uložení logu je nutné volit možnost "Publikovat", nikoliv' 'pouze "Uložit koncept". ' "Import proběhne na pozadí a může trvat až několik minut. " "Dejte si po spuštění importu kávu a potom obnovte stránku pro " "zobrazení výsledku importu." ), ], "import z Jekyll repozitáře", ), ] ### RELATIONS parent_page_types = ["main.MainHomePage"] subpage_types = ["main.MainArticlePage"] ### PANELS content_panels = Page.content_panels + [FieldPanel("perex"), FieldPanel("timeline")] promote_panels = make_promote_panels() ### EDIT HANDLERS edit_handler = TabbedInterface( [ ObjectList(content_panels, heading="Obsah"), ObjectList(promote_panels, heading="Propagovat"), ObjectList(import_panels, heading="Import"), ] ) ### OTHERS base_form_class = JekyllImportForm class Meta: verbose_name = "Rozcestník článků" def get_article_data_list(self): last_month = timezone.now().today().replace(day=1) - timedelta(days=1) first_day_of_last_month = last_month.replace(day=1) sorted_article_qs = MainArticlePage.objects.filter( date__gt=first_day_of_last_month ).order_by("-date") article_data_list = [] current_month_data = self.get_empty_month_data(timezone.now().date()) article_counter = 1 for article in sorted_article_qs: if article.date.month != current_month_data["month_number"]: article_data_list.append(current_month_data) # append completed month current_month_data = self.get_empty_month_data(article.date) article_counter = 1 current_column = "left_column" if article_counter % 2 else "right_column" current_month_data[current_column].append(article) article_counter += 1 article_data_list.append(current_month_data) # last iteration return article_data_list def get_context(self, request, *args, **kwargs): ctx = super().get_context(request, args, kwargs) ctx["article_data_list"] = self.get_article_data_list() return ctx @staticmethod def get_empty_month_data(date_obj): return { "month_number": date_obj.month, "month_text": date_obj.strftime("%B"), "left_column": [], "right_column": [], } class MainArticleTag(TaggedItemBase): content_object = ParentalKey("main.MainArticlePage", on_delete=models.CASCADE) class MainArticlePage( ArticleMixin, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page ): ### FIELDS article_type = models.PositiveSmallIntegerField( "Typ článku", choices=ARTICLE_TYPES.choices, default=ARTICLE_TYPES.PRESS_RELEASE ) content = StreamField( [ ("text", RichTextBlock(template="")), ("quote", blocks.ArticleQuoteBlock()), ("download", blocks.ArticleDownloadBlock()), ("image", blocks.ArticleImageBlock()), ], verbose_name="Článek", blank=True, ) author_page = models.ForeignKey( "main.MainPersonPage", on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Stránka autora (osoby)", ) region = models.IntegerField( choices=REGION_CHOICES, null=True, blank=True, verbose_name="Kraj", help_text="Kraj, ke kterému se článek vztahuje", ) tags = ClusterTaggableManager(through=MainArticleTag, blank=True) ### PANELS content_panels = ArticleMixin.content_panels + [ FieldPanel("article_type"), FieldPanel("author_page"), FieldPanel("region"), FieldPanel("tags"), ] promote_panels = make_promote_panels( admin_help.build(admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX), search_image=False, ) ### RELATIONS parent_page_types = ["main.MainArticlesPage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Aktualita" # def get_context(self, request): chceme/nechceme? # context = super().get_context(request) # context["related_articles"] = ( # self.get_siblings(inclusive=False) # .live() # .specific() # .order_by("-mainarticlepage__date")[:3] # ) # return context class MainProgramPage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page): ### FIELDS perex = models.TextField() program = StreamField( [("program_group", blocks.ProgramGroupBlock(label="Část programu"))], verbose_name="Program", blank=True, ) ### PANELS content_panels = Page.content_panels + [FieldPanel("perex"), FieldPanel("program")] promote_panels = make_promote_panels() settings_panels = [] ### RELATIONS parent_page_types = ["main.MainHomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Program" class MainPeoplePage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page): ### FIELDS perex = models.TextField() people = StreamField( [("people_group", blocks.PeopleGroupBlock(label="Seznam osob"))], verbose_name="Lidé", blank=True, ) ### PANELS content_panels = Page.content_panels + [FieldPanel("perex"), FieldPanel("people")] promote_panels = make_promote_panels() settings_panels = [] ### RELATIONS parent_page_types = ["main.MainHomePage"] subpage_types = ["main.MainPersonPage"] ### OTHERS class Meta: verbose_name = "Lidé" class MainPersonPage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page): ### FIELDS before_name = models.CharField( "Tituly před jménem", max_length=16, blank=True, null=True ) after_name = models.CharField( "Tituly za jménem", max_length=16, blank=True, null=True ) position = models.CharField( "Pozice/povolání", max_length=128, blank=True, null=True ) perex = models.TextField() text = RichTextField() twitter_username = models.CharField( "Uživatelské jméno twitter pro získání příspěvků", blank=True, null=True, max_length=32, ) email = models.CharField("E-mail", max_length=128, blank=True, null=True) phone = models.CharField("Telefonní kontakt", max_length=16, blank=True, null=True) facebook = models.URLField("Odkaz na Facebook", blank=True, null=True) twitter = models.URLField("Odkaz na Twitter", blank=True, null=True) instagram = models.URLField("Odkaz na Instagram", blank=True, null=True) settings_panels = [] ### RELATIONS parent_page_types = ["main.MainPeoplePage"] subpage_types = [] ### PANELS content_panels = Page.content_panels + [ FieldPanel("before_name"), FieldPanel("after_name"), FieldPanel("position"), FieldPanel("perex"), FieldPanel("twitter_username"), FieldPanel("text"), FieldPanel("email"), FieldPanel("phone"), FieldPanel("facebook"), FieldPanel("twitter"), FieldPanel("instagram"), ] def get_context(self, request): context = super().get_context(request) context["article_page_list"] = MainArticlePage.objects.filter( author_page=self.id ) context["tweet_list"] = Tweet.objects.filter( author_username=self.twitter_username ) return context ### OTHERS class Meta: verbose_name = "Detail osoby" # ordering = ("title",) def get_background_photo(self): """ Vrací background_photo pro pozadí na stránce, pokud není nastaveno, vezme falbback z homepage """ return ( self.background_photo if self.background_photo else self.root_page.fallback_image ) class MainContactPage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page): ### FIELDS contact_people = StreamField( [("item", blocks.PersonContactBlock())], verbose_name="Kontaktní osoby", blank=True, ) contact_boxes = StreamField( [("item", blocks.PersonContactBlock())], verbose_name="Kontaktní boxy", blank=True, ) text = RichTextField("Text", blank=True, features=RICH_TEXT_DEFAULT_FEATURES) ### PANELS content_panels = Page.content_panels + [ FieldPanel("contact_people"), FieldPanel("contact_boxes"), FieldPanel("text"), ] promote_panels = make_promote_panels() settings_panels = [] ### RELATIONS parent_page_types = ["main.MainHomePage"] subpage_types = [] ### OTHERS class Meta: verbose_name = "Kontakty"