from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.db import models from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin, route from wagtail.wagtailadmin.edit_handlers import FieldPanel, StreamFieldPanel from wagtail.wagtailcore import blocks from wagtail.wagtailcore.fields import RichTextField, StreamField from wagtail.wagtailcore.models import Page from wagtail.wagtailimages.blocks import ImageChooserBlock from wagtail.wagtailimages.edit_handlers import ImageChooserPanel # Page pouvant afficher des actualités class COFActuIndexMixin: @property def actus(self): actus = COFActuPage.objects.live().order_by("-date_start").descendant_of(self) return actus # Racine du site du COF class COFRootPage(Page, COFActuIndexMixin): introduction = RichTextField("Introduction") content_panels = Page.content_panels + [ FieldPanel("introduction", classname="full") ] subpage_types = ["COFActuIndexPage", "COFPage", "COFDirectoryPage", "COFUtilPage"] class Meta: verbose_name = "Racine site du COF" verbose_name_plural = "Racines site du COF" # Block iframe class IFrameBlock(blocks.StructBlock): url = blocks.URLBlock("Adresse de la page") height = blocks.CharBlock("Hauteur (en pixels)") class Meta: verbose_name = "Page incluse (iframe, à utiliser avec précaution)" verbose_name_plural = "Pages incluses (iframes, à utiliser avec précaution)" template = "cofcms/iframe_block.html" # Page lambda du site class COFPage(Page): body = StreamField( [ ("heading", blocks.CharBlock(classname="full title")), ("paragraph", blocks.RichTextBlock()), ("image", ImageChooserBlock()), ("iframe", IFrameBlock()), ] ) content_panels = Page.content_panels + [StreamFieldPanel("body")] subpage_types = ["COFDirectoryPage", "COFPage"] parent_page_types = ["COFPage", "COFRootPage"] class Meta: verbose_name = "Page normale COF" verbose_name_plural = "Pages normales COF" # Actualités class COFActuIndexPage(Page, COFActuIndexMixin): subpage_types = ["COFActuPage"] parent_page_types = ["COFRootPage"] class Meta: verbose_name = "Index des actualités" verbose_name_plural = "Indexs des actualités" def get_context(self, request): context = super().get_context(request) actus = COFActuPage.objects.live().descendant_of(self).order_by("-date_end") page = request.GET.get("page") paginator = Paginator(actus, 5) try: actus = paginator.page(page) except PageNotAnInteger: actus = paginator.page(1) except EmptyPage: actus = paginator.page(paginator.num_pages) context["actus"] = actus return context class COFActuPage(RoutablePageMixin, Page): chapo = models.TextField("Description rapide", blank=True) body = RichTextField("Contenu") image = models.ForeignKey( "wagtailimages.Image", verbose_name="Image à la Une", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) is_event = models.BooleanField("Évènement", default=True, blank=True) date_start = models.DateTimeField("Date et heure de début") date_end = models.DateTimeField( "Date et heure de fin", blank=True, default=None, null=True ) all_day = models.BooleanField("Toute la journée", default=False, blank=True) content_panels = Page.content_panels + [ ImageChooserPanel("image"), FieldPanel("chapo"), FieldPanel("body", classname="full"), FieldPanel("is_event"), FieldPanel("date_start"), FieldPanel("date_end"), FieldPanel("all_day"), ] subpage_types = [] parent_page_types = ["COFActuIndexPage"] class Meta: verbose_name = "Actualité" verbose_name_plural = "Actualités" # Annuaires (Clubs, partenaires, bonnes adresses) class COFDirectoryPage(Page): introduction = RichTextField("Introduction") alphabetique = models.BooleanField( "Tri par ordre alphabétique ?", default=True, blank=True ) content_panels = Page.content_panels + [ FieldPanel("introduction"), FieldPanel("alphabetique"), ] subpage_types = ["COFActuPage", "COFDirectoryEntryPage"] parent_page_types = ["COFRootPage", "COFPage"] @property def entries(self): entries = COFDirectoryEntryPage.objects.live().descendant_of(self) if self.alphabetique: entries = entries.order_by("title") return entries class Meta: verbose_name = "Annuaire (clubs, partenaires, bons plans...)" verbose_name_plural = "Annuaires" class COFDirectoryEntryPage(Page): body = RichTextField("Description") links = StreamField( [ ( "lien", blocks.StructBlock( [ ("url", blocks.URLBlock(required=True)), ("texte", blocks.CharBlock()), ] ), ), ( "contact", blocks.StructBlock( [ ("email", blocks.EmailBlock(required=True)), ("texte", blocks.CharBlock()), ] ), ), ] ) image = models.ForeignKey( "wagtailimages.Image", verbose_name="Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) content_panels = Page.content_panels + [ ImageChooserPanel("image"), FieldPanel("body", classname="full"), StreamFieldPanel("links"), ] subpage_types = [] parent_page_types = ["COFDirectoryPage"] class Meta: verbose_name = "Entrée d'annuaire" verbose_name_plural = "Entrées d'annuaire" # Pour le calendrier, ne doit pas être pris par ModelTranslation class COFUtilPage(RoutablePageMixin, Page): # Mini calendrier @route(r"^calendar/(\d+)/(\d+)/$") def calendar(self, request, year, month): from .views import raw_calendar_view return raw_calendar_view(request, int(year), int(month)) """ ModelTranslation override le système des @route de wagtail, ce qui empêche COFUtilPage d'être une page traduite pour pouvoir l'utiliser. Ce qui fait planter `get_absolute_url` pour des problèmes d'héritage des pages parentes (qui sont, elles, traduites). Le seul moyen trouvé pour résoudre ce problème est de faire une autre fonction à qui on fournit request en argument (donc pas un override de get_absolute_url). TODO : vérifier si ces problèmes ont été résolus dans les màj de wagtail et modeltranslation """ def debugged_get_url(self, request): parent = COFRootPage.objects.parent_of(self).live().first() burl = parent.relative_url(request.site) return burl + self.slug class Meta: verbose_name = "Page utilitaire" verbose_name_plural = "Pages utilitaires"