dnscms: better organizer chooser, fixes slugs for organizers, better slugs
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class DnsCmsConfig(AppConfig):
|
||||||
|
name = "dnscms"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
from dnscms import signals # noqa: F401
|
||||||
@@ -173,7 +173,7 @@ MEDIA_URL = "/media/"
|
|||||||
# Wagtail settings
|
# Wagtail settings
|
||||||
|
|
||||||
WAGTAIL_SITE_NAME = "dnscms"
|
WAGTAIL_SITE_NAME = "dnscms"
|
||||||
WAGTAIL_ALLOW_UNICODE_SLUGS = False
|
WAGTAIL_ALLOW_UNICODE_SLUGS = True
|
||||||
# Headless: the Next.js frontend uses trailing-slash-free URLs, so strip
|
# Headless: the Next.js frontend uses trailing-slash-free URLs, so strip
|
||||||
# trailing slashes from links generated by Wagtail (e.g. the GraphQL `url` field).
|
# trailing slashes from links generated by Wagtail (e.g. the GraphQL `url` field).
|
||||||
WAGTAIL_APPEND_SLASH = False
|
WAGTAIL_APPEND_SLASH = False
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
from django.db.models.signals import pre_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from wagtail.models import Page
|
||||||
|
|
||||||
|
from dnscms.utils import slugify
|
||||||
|
|
||||||
|
SLUGGED_SNIPPETS = {"events.EventOrganizer", "events.EventCategory"}
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_save)
|
||||||
|
def normalize_slug(sender, instance, **kwargs):
|
||||||
|
label = f"{sender._meta.app_label}.{sender.__name__}"
|
||||||
|
if isinstance(instance, Page) or label in SLUGGED_SNIPPETS:
|
||||||
|
if getattr(instance, "slug", None):
|
||||||
|
instance.slug = slugify(instance.slug)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.utils.text import slugify as django_slugify
|
||||||
|
|
||||||
|
NORWEGIAN_TRANSLITERATIONS = str.maketrans({"æ": "ae", "ø": "o", "å": "a"})
|
||||||
|
|
||||||
|
|
||||||
|
def slugify(value: str) -> str:
|
||||||
|
return django_slugify(value.lower().translate(NORWEGIAN_TRANSLITERATIONS))
|
||||||
@@ -166,7 +166,7 @@ class EventOrganizerLink(Orderable):
|
|||||||
|
|
||||||
@register_snippet
|
@register_snippet
|
||||||
@register_query_field("eventOrganizer", "eventOrganizers")
|
@register_query_field("eventOrganizer", "eventOrganizers")
|
||||||
class EventOrganizer(ClusterableModel):
|
class EventOrganizer(index.Indexed, ClusterableModel):
|
||||||
objects = WPAwareManager()
|
objects = WPAwareManager()
|
||||||
|
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
@@ -222,6 +222,11 @@ class EventOrganizer(ClusterableModel):
|
|||||||
GraphQLString("external_url"),
|
GraphQLString("external_url"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
search_fields = [
|
||||||
|
index.SearchField("name"),
|
||||||
|
index.AutocompleteField("name"),
|
||||||
|
]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("event organizer")
|
verbose_name = _("event organizer")
|
||||||
verbose_name_plural = _("event organizers")
|
verbose_name_plural = _("event organizers")
|
||||||
|
|||||||
+19
-1
@@ -1,6 +1,24 @@
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from wagtail.admin.forms import WagtailAdminModelForm
|
||||||
from wagtail.admin.viewsets.chooser import ChooserViewSet
|
from wagtail.admin.viewsets.chooser import ChooserViewSet
|
||||||
|
|
||||||
|
from dnscms.utils import slugify
|
||||||
|
from events.models import EventOrganizer
|
||||||
|
|
||||||
|
|
||||||
|
class EventOrganizerCreationForm(WagtailAdminModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = EventOrganizer
|
||||||
|
fields = ["name", "association", "external_url"]
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
instance = super().save(commit=False)
|
||||||
|
if not instance.slug:
|
||||||
|
instance.slug = slugify(instance.name)
|
||||||
|
if commit:
|
||||||
|
instance.save()
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class EventOrganizerChooserViewSet(ChooserViewSet):
|
class EventOrganizerChooserViewSet(ChooserViewSet):
|
||||||
model = "events.EventOrganizer"
|
model = "events.EventOrganizer"
|
||||||
@@ -10,7 +28,7 @@ class EventOrganizerChooserViewSet(ChooserViewSet):
|
|||||||
choose_one_text = _("Choose an organizer")
|
choose_one_text = _("Choose an organizer")
|
||||||
choose_another_text = _("Choose another organizer")
|
choose_another_text = _("Choose another organizer")
|
||||||
edit_item_text = _("Edit this organizer")
|
edit_item_text = _("Edit this organizer")
|
||||||
form_fields = ["name", "association", "external_url"]
|
creation_form_class = EventOrganizerCreationForm
|
||||||
|
|
||||||
|
|
||||||
event_organizer_chooser_viewset = EventOrganizerChooserViewSet("event_organizer_chooser")
|
event_organizer_chooser_viewset = EventOrganizerChooserViewSet("event_organizer_chooser")
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from events.models import (
|
|||||||
EventOrganizerLink,
|
EventOrganizerLink,
|
||||||
EventPage,
|
EventPage,
|
||||||
)
|
)
|
||||||
|
from events.views import EventOrganizerCreationForm
|
||||||
from tests.conftest import (
|
from tests.conftest import (
|
||||||
AssociationPageFactory,
|
AssociationPageFactory,
|
||||||
CustomImageFactory,
|
CustomImageFactory,
|
||||||
@@ -118,6 +119,29 @@ def test_eventoccurrence_clean_promotes_matching_custom_text_to_venue(event_inde
|
|||||||
assert occurrence.venue_custom == ""
|
assert occurrence.venue_custom == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_organizer_creation_form_auto_slugifies_name(db):
|
||||||
|
form = EventOrganizerCreationForm(data={"name": "Forening for ÆØÅ", "external_url": ""})
|
||||||
|
|
||||||
|
assert form.is_valid(), form.errors
|
||||||
|
organizer = form.save()
|
||||||
|
|
||||||
|
assert organizer.pk is not None
|
||||||
|
assert organizer.name == "Forening for ÆØÅ"
|
||||||
|
assert organizer.slug == "forening-for-aeoa"
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_organizer_creation_form_keeps_explicit_slug(db):
|
||||||
|
organizer = EventOrganizer(name="Forening", slug="custom-slug")
|
||||||
|
form = EventOrganizerCreationForm(
|
||||||
|
data={"name": "Forening", "external_url": ""}, instance=organizer
|
||||||
|
)
|
||||||
|
|
||||||
|
assert form.is_valid(), form.errors
|
||||||
|
organizer = form.save()
|
||||||
|
|
||||||
|
assert organizer.slug == "custom-slug"
|
||||||
|
|
||||||
|
|
||||||
def test_eventoccurrence_clean_keeps_custom_text_when_no_venue_matches(event_index):
|
def test_eventoccurrence_clean_keeps_custom_text_when_no_venue_matches(event_index):
|
||||||
event = EventPageFactory(parent=event_index)
|
event = EventPageFactory(parent=event_index)
|
||||||
occurrence = EventOccurrence(
|
occurrence = EventOccurrence(
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from dnscms.utils import slugify
|
||||||
|
from events.models import EventCategory, EventOrganizer
|
||||||
|
from tests.conftest import GenericPageFactory
|
||||||
|
|
||||||
|
|
||||||
|
def test_slugify_transliterates_norwegian_letters():
|
||||||
|
assert slugify("Bjørn") == "bjorn"
|
||||||
|
assert slugify("Møterom") == "moterom"
|
||||||
|
assert slugify("Forening for ÆØÅ") == "forening-for-aeoa"
|
||||||
|
|
||||||
|
|
||||||
|
def test_slugify_is_idempotent_on_ascii():
|
||||||
|
assert slugify("already-clean-slug") == "already-clean-slug"
|
||||||
|
|
||||||
|
|
||||||
|
def test_page_save_transliterates_unicode_in_slug(home_page):
|
||||||
|
page = GenericPageFactory(parent=home_page, title="Møterom", slug="møterom")
|
||||||
|
|
||||||
|
assert page.slug == "moterom"
|
||||||
|
|
||||||
|
|
||||||
|
def test_page_save_leaves_clean_slug_untouched(home_page):
|
||||||
|
page = GenericPageFactory(parent=home_page, title="Om oss", slug="om-oss")
|
||||||
|
|
||||||
|
assert page.slug == "om-oss"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_organizer_save_transliterates_unicode_in_slug():
|
||||||
|
organizer = EventOrganizer.objects.create(name="Bjørn", slug="bjørn")
|
||||||
|
|
||||||
|
assert organizer.slug == "bjorn"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_category_save_transliterates_unicode_in_slug():
|
||||||
|
category = EventCategory.objects.create(name="Mørkerom", slug="mørkerom")
|
||||||
|
|
||||||
|
assert category.slug == "morkerom"
|
||||||
Reference in New Issue
Block a user