from django.db import models from django.utils import timezone from modelcluster.contrib.taggit import ClusterTaggableManager from modelcluster.fields import ParentalKey from taggit.models import ItemBase, TagBase from wagtail.admin.panels import ( FieldPanel, InlinePanel, MultiFieldPanel, ObjectList, TabbedInterface, ) from wagtail.blocks import PageChooserBlock from wagtail.contrib.routable_page.models import RoutablePageMixin, path from wagtail.contrib.settings.models import BaseSiteSetting, register_setting from wagtail.documents import get_document_model from wagtail.fields import RichTextField, StreamField from wagtail.models import Page from wagtail_color_panel.edit_handlers import NativeColorPanel from wagtail_color_panel.fields import ColorField from .blocks import PersonBlock # --- BEGIN Tags --- class Tag(TagBase): bg_color = ColorField(verbose_name="Barva pozadí", default="#fafafa") fg_color = ColorField(verbose_name="Barva textu", default="#000000") panels = [ FieldPanel("name"), FieldPanel("slug"), NativeColorPanel("bg_color"), NativeColorPanel("fg_color"), ] class TaggedArticle(ItemBase): content_object = ParentalKey( "home.HomeArticlePage", on_delete=models.CASCADE, related_name="tagged_items" ) tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name="article_tags") # --- END Tags --- class HomePage(RoutablePageMixin, Page): heading_text = RichTextField(verbose_name="Hlavní text stránky") # --- Donations --- donation_text = RichTextField(verbose_name="Text pro dary") # --- Contact info --- address = models.CharField(verbose_name="Sídlo", max_length=128) branch = models.CharField(verbose_name="Pobočka", max_length=128) email = models.EmailField(verbose_name="Email", max_length=128) ds_id = models.CharField(verbose_name="Datová schránka", max_length=128) # --- People --- director = StreamField( [ ("person", PersonBlock()), ( "person_page", PageChooserBlock( page_type="home.HomePersonPage", label="Stránka osoby", icon="user" ), ), ], verbose_name="Ředitel", use_json_field=True, blank=True, null=True, ) director_description = RichTextField(verbose_name="Ředitel - popis") academic_council = StreamField( [ ("person", PersonBlock()), ( "person_page", PageChooserBlock( page_type="home.HomePersonPage", label="Stránka osoby", icon="user" ), ), ], verbose_name="Akademická rada", use_json_field=True, blank=True, null=True, ) academic_council_description = RichTextField(verbose_name="Akademická rada - popis") controller = StreamField( [ ("person", PersonBlock()), ( "person_page", PageChooserBlock( page_type="home.HomePersonPage", label="Stránka osoby", icon="user" ), ), ], verbose_name="Kontrolor", use_json_field=True, blank=True, null=True, ) controller_description = RichTextField(verbose_name="Kontrolor - popis") council_members = StreamField( [ ("person", PersonBlock()), ( "person_page", PageChooserBlock( page_type="home.HomePersonPage", label="Stránka osoby", icon="user" ), ), ], verbose_name="Správní rada", use_json_field=True, blank=True, null=True, ) council_members_description = RichTextField(verbose_name="Správní rada - popis") volunteers = StreamField( [ ("person", PersonBlock()), ( "person_page", PageChooserBlock( page_type="home.HomePersonPage", label="Stránka osoby", icon="user" ), ), ], verbose_name="Dobrovolníci", use_json_field=True, blank=True, null=True, ) volunteers_description = RichTextField(verbose_name="Dobrovolníci - popis") employees = StreamField( [ ("person", PersonBlock()), ( "person_page", PageChooserBlock( page_type="home.HomePersonPage", label="Stránka osoby", icon="user" ), ), ], verbose_name="Zaměstnanci", use_json_field=True, blank=True, null=True, ) employees_description = RichTextField(verbose_name="Zaměstnanci - popis") subpage_types = [ "home.HomeArticlesPage", "home.HomeEventsPage", "home.HomeDocumentsPage", "home.HomeVideosPage", "home.HomePeoplePage", ] intro_panels = Page.content_panels + [ FieldPanel("heading_text", icon="pilcrow"), FieldPanel("donation_text", icon="pilcrow"), MultiFieldPanel( [ FieldPanel("address", icon="home"), FieldPanel("branch", icon="home"), FieldPanel("email", icon="pilcrow"), FieldPanel("ds_id", icon="mail"), ], heading="Kontaktní údaje", ), ] people_panels = [ FieldPanel("director_description", icon="pilcrow"), FieldPanel("director", icon="user"), FieldPanel("academic_council_description"), FieldPanel("academic_council", icon="user"), FieldPanel("controller_description", icon="pilcrow"), FieldPanel("controller", icon="user"), FieldPanel("council_members_description", icon="pilcrow"), FieldPanel("council_members", icon="group"), FieldPanel("volunteers_description", icon="pilcrow"), FieldPanel("volunteers", icon="group"), FieldPanel("employees_description", icon="pilcrow"), FieldPanel("employees", icon="group"), ] edit_handler = TabbedInterface( [ ObjectList(intro_panels, heading="Základy"), ObjectList(people_panels, heading="Lidé"), ObjectList(Page.promote_panels, heading="Propagace"), ] ) # Articles @property def articles_page(self) -> "HomeArticlesPage": return HomeArticlesPage.objects.live().first() @property def latest_articles(self) -> "QuerySet": return HomeArticlePage.objects.order_by("-date").live().all()[:3] # Events @property def events_page(self) -> "HomeEventsPage": return HomeEventsPage.objects.live().first() @property def latest_events(self) -> "QuerySet": return HomeEventPage.objects.order_by("-date").live().all()[:8] # Documents @property def documents_page(self) -> "HomeDocumentsPage": return HomeDocumentsPage.objects.child_of(self).live().first() @property def latest_documents(self) -> list: documents = list( HomeDocumentPage.objects.child_of(self.documents_page) .order_by("-date") .live() .all()[:4] ) # Pad documents list so it's always 4 items long documents += [None] * (4 - len(documents)) document_directories = list( HomeDocumentsPage.objects.child_of(self.documents_page).live().all()[:4] ) # Replace 0-4 last items in the list with directories position_in_documents = 3 for document_directory in document_directories: documents[position_in_documents] = document_directory position_in_documents -= 1 # Then remove the Nones we padded the list with return list(filter(lambda document: document is not None, documents)) # Feed @path("feeds/atom/") def view_feed(self, request): # Avoid circular import from .feeds import LatestArticlesFeed # noqa return LatestArticlesFeed()(request, self.articles_page.id) class Meta: verbose_name = "Domovská stránka" # --- BEGIN Articles, events, videos and documents --- class HomeArticlesPage(Page): content = RichTextField(verbose_name="Obsah", blank=True, null=True) parent_page_type = ["home.HomePage"] subpage_types = ["home.HomeArticlePage"] content_panels = Page.content_panels + [ FieldPanel("content", icon="pilcrow"), ] @property def articles(self): return HomeArticlePage.objects.live().order_by("-date") def get_context(self, request): context = super().get_context(request) articles = self.articles # Filter by tag tag = request.GET.get("tag") if tag: articles = articles.filter(tags__name=tag) context["filtered_tag"] = tag context["articles"] = articles return context class Meta: verbose_name = "Rozcestník článků" class HomeEventsPage(Page): content = RichTextField(verbose_name="Obsah", blank=True, null=True) parent_page_type = ["home.HomePage"] subpage_types = ["home.HomeEventPage"] content_panels = Page.content_panels + [ FieldPanel("content", icon="pilcrow"), ] @property def events(self): return HomeEventPage.objects.live().order_by("-date").all() class Meta: verbose_name = "Rozcestník akcí" class HomeDocumentsPage(Page): content = RichTextField(verbose_name="Obsah", blank=True, null=True) parent_page_type = ["home.HomePage"] subpage_types = ["home.HomeDocumentPage", "home.HomeDocumentsPage"] content_panels = Page.content_panels + [ FieldPanel("content", icon="pilcrow"), ] @property def documents(self): documents = list( HomeDocumentPage.objects.child_of(self).order_by("-date").live().all() ) document_directories = list( HomeDocumentsPage.objects.child_of(self).live().all() ) return documents + document_directories class Meta: verbose_name = "Rozcestník dokumentů" class HomeVideosPage(Page): content = RichTextField(verbose_name="Obsah", blank=True, null=True) parent_page_type = ["home.HomePage"] subpage_types = ["home.HomeVideoPage"] content_panels = Page.content_panels + [ FieldPanel("content", icon="pilcrow"), ] @property def videos(self): return HomeVideoPage.objects.live().order_by("-date").all() class Meta: verbose_name = "Rozcestník videí" class HomeContentPageMixin(Page): author_page = models.ForeignKey( "home.HomePersonPage", on_delete=models.SET_NULL, blank=True, null=True, verbose_name="Stránka autora", help_text="Pokud je vybrána stránka, není nutno vyplňovat jméno autora níže.", ) author = models.CharField( verbose_name="Jméno autora", max_length=128, blank=True, null=True, ) date = models.DateField(verbose_name="Datum vytvoření", default=timezone.now) content = RichTextField(verbose_name="Obsah") parent_page_type = ["home.HomeArticlesPage"] content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel("author_page", icon="user"), FieldPanel("author", icon="user"), ], heading="Autor", ), FieldPanel("date", icon="calendar"), FieldPanel("content", icon="pilcrow"), ] @property def shortened_perex(self) -> str: if len(self.perex) > 310: return self.perex[:300] + "..." return self.perex class Meta: abstract = True class HomeArticlePage(HomeContentPageMixin): image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", verbose_name="Obrázek", ) content = RichTextField( verbose_name="Obsah", features=[ "h2", "h3", "h4", "bold", "italic", "ol", "ul", "hr", "link", "document-link", "image", "embed", "footnotes", ], ) show_image_on_homepage = models.BooleanField( verbose_name="Zobrazovat obrázek na homepage", default=False, ) tags = ClusterTaggableManager( through=TaggedArticle, blank=True, verbose_name="Štítky" ) perex = models.TextField(verbose_name="Perex") content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel("author_page", icon="user"), FieldPanel("author", icon="user"), ], heading="Autor", ), MultiFieldPanel( [ FieldPanel("image", icon="image", heading=" "), FieldPanel("show_image_on_homepage"), ], heading="Obrázek", ), FieldPanel("date", icon="calendar"), FieldPanel("perex", icon="pilcrow"), FieldPanel("tags", icon="tag"), FieldPanel("content", icon="pilcrow"), InlinePanel("footnotes", label="Footnotes", icon="pilcrow"), ] class Meta: verbose_name = "Článek" class HomeEventPage(HomeContentPageMixin): date = models.DateField(verbose_name="Datum konání", blank=True, null=True) location = models.CharField( verbose_name="Místo konání", blank=True, null=True, max_length=64 ) content = RichTextField(verbose_name="Obsah", blank=True, null=True) content_panels = Page.content_panels + [ FieldPanel("date", icon="calendar"), FieldPanel("location", icon="globe"), MultiFieldPanel( [ FieldPanel("author_page", icon="user"), FieldPanel("author", icon="user"), ], heading="Autor", ), FieldPanel("content", icon="pilcrow"), ] class Meta: verbose_name = "Akce" class HomeDocumentPage(HomeContentPageMixin): document = models.ForeignKey( get_document_model(), on_delete=models.PROTECT, verbose_name="Dokument" ) content = RichTextField(verbose_name="Obsah", blank=True, null=True) subpage_types = ["home.HomeDocumentPage"] content_panels = Page.content_panels + [ FieldPanel("document", icon="doc-full"), MultiFieldPanel( [ FieldPanel("author_page", icon="user"), FieldPanel("author", icon="user"), ], heading="Autor", ), FieldPanel("date", icon="calendar"), FieldPanel("content", icon="pilcrow"), ] class Meta: verbose_name = "Dokument" class HomeVideoPage(HomeContentPageMixin): embed_url = models.URLField( verbose_name="URL Embedu", help_text="Pro získání adresy zmáčkni tlačítko Sdílet, vyber záložku Embed a zaškrtní zobrazování pouze URL.", ) thumbnail = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", verbose_name="Náhledový obrázek", ) content = RichTextField(verbose_name="Obsah", blank=True, null=True) content_panels = Page.content_panels + [ FieldPanel("embed_url", icon="link"), FieldPanel("thumbnail", icon="image"), MultiFieldPanel( [ FieldPanel("author_page", icon="user"), FieldPanel("author", icon="user"), ], heading="Autor", ), FieldPanel("date", icon="calendar"), FieldPanel("content", icon="pilcrow"), ] class Meta: verbose_name = "Video" # --- END Articles, events, videos and documents --- # --- BEGIN People --- class HomePeoplePage(Page): content = RichTextField(verbose_name="Obsah", blank=True, null=True) parent_page_type = ["home.HomePage"] subpage_types = ["home.HomePersonPage"] content_panels = Page.content_panels + [ FieldPanel("content", icon="pilcrow"), ] @property def people(self): return HomePersonPage.objects.live().order_by("title").all() class Meta: verbose_name = "Rozcestník osob" class HomePersonPage(Page): image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", verbose_name="Profilový obrázek", ) name_titles = models.CharField( max_length=32, blank=True, null=True, verbose_name="Tituly", ) position = models.TextField(verbose_name="Pracovní pozice", blank=True, null=True) email = models.EmailField(verbose_name="Emailová adresa", blank=True, null=True) description = RichTextField(verbose_name="Popis", blank=True, null=True) content_panels = Page.content_panels + [ FieldPanel("name_titles", icon="pilcrow"), FieldPanel("image", icon="image"), FieldPanel("position", icon="pilcrow"), FieldPanel("email", icon="mail"), FieldPanel("description", icon="pilcrow"), ] @property def full_name(self) -> str: name = self.title if self.name_titles is not None: name = f"{self.name_titles} {name}" return name @property def inline_position(self) -> str: """Returns this person's position formatted to fit on a single line.""" if self.position is None: return None split_positions = self.position.split("\n") split_positions = [position.strip() for position in split_positions] return ", ".join(split_positions) class Meta: verbose_name = "Osoba" # --- END People --- # --- BEGIN Settings --- @register_setting class SocialMediaSettings(BaseSiteSetting): mastodon = models.URLField(blank=True, null=True, help_text="Mastodon URL") twitter = models.URLField(blank=True, null=True, help_text="Twitter URL") linkedin = models.URLField(blank=True, null=True, help_text="LinkedIn URL") facebook = models.URLField(blank=True, null=True, help_text="Facebook URL") panels = [ MultiFieldPanel( [ FieldPanel("mastodon"), FieldPanel("twitter"), FieldPanel("linkedin"), FieldPanel("facebook"), ], heading="Nastavení sociálních sítí", ) ] class Meta: verbose_name = "Sociální sítě" # --- END Settings ---