Fix Module slug generation

This commit is contained in:
Lorenz Padberg 2024-04-12 11:13:12 +02:00
parent 101670355e
commit f398839765
3 changed files with 76 additions and 9 deletions

View File

@ -3,12 +3,14 @@ from django.db import models
from django.utils import timezone
from django.utils.translation import gettext as _
from wagtail.admin.forms import WagtailAdminPageForm
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList, TitleFieldPanel
from wagtail.fields import RichTextField
from django.conf import settings
from core.constants import DEFAULT_RICH_TEXT_FEATURES
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
from users.models import SchoolClass
from django.utils.text import slugify
EXACT = "exact"
@ -54,9 +56,10 @@ class ModuleCategory(models.Model):
class ModulePageForm(WagtailAdminPageForm):
def clean(self):
cleaned_data = super().clean()
print("cleaning")
if "slug" in self.cleaned_data:
page_slug = cleaned_data["slug"]
if not Module._slug_is_available(page_slug, self.instance):
if not Module._slug_is_available(page_slug, self.parent_page, self.instance):
self.add_error(
"slug",
forms.ValidationError(
@ -97,7 +100,7 @@ class Module(StrictHierarchyPage):
solutions_enabled_for = models.ManyToManyField(SchoolClass)
content_panels = [
FieldPanel("title", classname="full title"),
TitleFieldPanel("title", classname="full title"),
FieldPanel("meta_title", classname="full title"),
FieldPanel("level"),
FieldPanel("category"),
@ -106,7 +109,7 @@ class Module(StrictHierarchyPage):
FieldPanel("teaser"),
FieldPanel("intro"),
]
base_form_class = ModulePageForm
# base_form_class = ModulePageForm
edit_handler = TabbedInterface(
[ObjectList(content_panels, heading="Content"), get_default_settings()]
@ -181,11 +184,42 @@ class Module(StrictHierarchyPage):
return f"{self.meta_title} - {self.title}"
@staticmethod
def _slug_is_available(slug, page):
# modeled after `Page._slug_is_available`
modules = Module.objects.filter(slug=slug).not_page(page)
def _slug_is_available(slug, parent_page, page=None):
"""
return not modules.exists()
# modeled after `Page._slug_is_available`
Determine whether the given slug is available for use on a child page of
parent_page. If 'page' is passed, the slug is intended for use on that page
(and so it will be excluded from the duplicate check).
"""
if parent_page is None:
# the root page's slug can be whatever it likes...
return True
modules = Module.objects.all()
if page:
modules = modules.not_page(page)
return not modules.filter(slug=slug).exists()
def _get_autogenerated_slug(self, base_slug):
# modeled after `Page._get_autogenerated_slug`
candidate_slug = base_slug
suffix = 1
parent_page = self.get_parent()
while not self._slug_is_available(candidate_slug, parent_page, self):
# try with incrementing suffix until we find a slug which is available
suffix += 1
candidate_slug = "%s-%d" % (base_slug, suffix)
return candidate_slug
def full_clean(self, *args, **kwargs):
super().full_clean(*args, **kwargs)
if not self._slug_is_available(self.slug, self.get_parent(), self):
self.slug = self._get_autogenerated_slug(self.slug)
class RecentModule(models.Model):

View File

@ -0,0 +1,32 @@
from django.test import TestCase, RequestFactory
from unittest import skip
from graphene.test import Client
from graphql_relay import to_global_id
from api.schema import schema
from api.utils import get_object
from books.models import ContentBlock, Chapter
from books.factories import ModuleFactory, ModuleLevelFactory, TopicFactory
from core.factories import UserFactory
from users.models import User
class TestModuleCreation(TestCase):
"""
Since the modules url in the frontend is not /topic/module but /module the slug has to be unique.
This test checks if the slug is generated correctly.
"""
def test_create_new_module_generates_slug(self):
topic = TopicFactory(title="Berufslehre")
module = ModuleFactory(title="Modul 1", parent=topic)
self.assertEqual("modul-1", module.slug)
def test_create_new_module_different_topic(self):
topic = TopicFactory(title="Berufslehre")
module = ModuleFactory(title="Modul 1", parent=topic)
topic2 = TopicFactory(title="Geld und Macht")
module2 = ModuleFactory(title="Modul 1", parent=topic2)
self.assertEqual("modul-1", module.slug)
self.assertEqual("modul-1-2", module2.slug, )

View File

@ -2,6 +2,7 @@ from django.contrib import admin
from wagtail.admin.panels import CommentPanel
from wagtail.admin.panels import FieldPanel, ObjectList
from wagtail.models import Page
from wagtail.admin.widgets.slug import SlugInput
class StrictHierarchyPage(Page):
@ -41,4 +42,4 @@ def wagtail_parent_filter(parent_cls, child_cls):
def get_default_settings():
return ObjectList([FieldPanel("slug", read_only=True), CommentPanel()], heading="Settings")
return ObjectList([FieldPanel("slug", widget=SlugInput), CommentPanel()], heading="Settings")