import re from django.conf import settings from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.db import models from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel 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.blocks import ImageChooserBlock from wagtail.images.edit_handlers import ImageChooserPanel # Récriture des URL publiques par surcharge de get_url class COFRewriteUrlMixin: def get_url_parts(self, request=None, current_site=None): (site_id, root_url, page_path) = super().get_url_parts(request) if page_path is None: return (site_id, root_url, page_path) pattern = getattr(settings, "SITECOF_INTERNAL_URL", r"^/(en/|fr/|)sitecof/") replace = getattr(settings, "SITECOF_PUBLIC_URL", "/\\1news/") page_path = re.sub(pattern, replace, page_path) return (site_id, root_url, page_path) # 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(COFRewriteUrlMixin, RoutablePageMixin, Page, COFActuIndexMixin): introduction = RichTextField("Introduction") content_panels = Page.content_panels + [ FieldPanel("introduction", classname="full") ] subpage_types = ["COFActuIndexPage", "COFPage", "COFDirectoryPage"] class Meta: verbose_name = "Racine site du COF" verbose_name_plural = "Racines site du COF" @property def actus(self): return super().actus[:4] # 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)) # Captcha Mailing-listes @route(r"^sympa/captcha/$") def sympa_captcha(self, request): from .views import sympa_captcha_form_view return sympa_captcha_form_view(request) # 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(COFRewriteUrlMixin, 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(COFRewriteUrlMixin, 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(COFRewriteUrlMixin, 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(COFRewriteUrlMixin, 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(COFRewriteUrlMixin, 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()), ] ), ), ], blank=True, ) 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"