From a999375f23c9104d7f887d250f4322d1234b8fd9 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 24 Jul 2023 13:34:08 +0200 Subject: [PATCH] Update slugs when parent changes slug due to title change --- server/config/settings/base.py | 1 + .../course/creators/test_course.py | 4 +- .../creators/versicherungsvermittlerin.py | 5 +-- server/vbv_lernwelt/course/models.py | 27 ++++++++++++- .../course/tests/test_model_save.py | 38 +++++++++++++++++++ server/vbv_lernwelt/course/utils.py | 15 ++++++++ 6 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 server/vbv_lernwelt/course/tests/test_model_save.py create mode 100644 server/vbv_lernwelt/course/utils.py diff --git a/server/config/settings/base.py b/server/config/settings/base.py index 10a80e6e..2136e4fd 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -244,6 +244,7 @@ WAGTAIL_PASSWORD_RESET_ENABLED = False WAGTAILUSERS_PASSWORD_ENABLED = False WAGTAIL_ENABLE_UPDATE_CHECK = False WAGTAIL_ENABLE_WHATS_NEW_BANNER = False +WAGTAIL_CONTENT_LANGUAGES = LANGUAGES WAGTAILDOCS_DOCUMENT_MODEL = "media_library.LibraryDocument" diff --git a/server/vbv_lernwelt/course/creators/test_course.py b/server/vbv_lernwelt/course/creators/test_course.py index a790bd09..2eaaae2d 100644 --- a/server/vbv_lernwelt/course/creators/test_course.py +++ b/server/vbv_lernwelt/course/creators/test_course.py @@ -3,7 +3,6 @@ from datetime import datetime from dateutil.relativedelta import MO, relativedelta, TH, TU from django.utils import timezone from slugify import slugify -from wagtail.models import Site from wagtail.rich_text import RichText from vbv_lernwelt.assignment.creators.create_assignments import ( @@ -34,6 +33,7 @@ from vbv_lernwelt.course.models import ( CourseSession, CourseSessionUser, ) +from vbv_lernwelt.course.utils import get_wagtail_default_site from vbv_lernwelt.course_session.models import ( CourseSessionAssignment, CourseSessionAttendanceCourse, @@ -231,7 +231,7 @@ def create_test_course_with_categories(apps=None, schema_editor=None): course_page = CoursePageFactory( title="Test Lehrgang", - parent=Site.objects.get(is_default_site=True).root_page, + parent=get_wagtail_default_site().root_page, course=course, ) course.slug = course_page.slug diff --git a/server/vbv_lernwelt/course/creators/versicherungsvermittlerin.py b/server/vbv_lernwelt/course/creators/versicherungsvermittlerin.py index 77f9f2b8..48fa0bc6 100644 --- a/server/vbv_lernwelt/course/creators/versicherungsvermittlerin.py +++ b/server/vbv_lernwelt/course/creators/versicherungsvermittlerin.py @@ -1,7 +1,6 @@ -from wagtail.models import Site - from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN_ID from vbv_lernwelt.course.factories import CoursePageFactory +from vbv_lernwelt.course.utils import get_wagtail_default_site def create_versicherungsvermittlerin_with_categories( @@ -43,7 +42,7 @@ def create_versicherungsvermittlerin_with_categories( course_page = CoursePageFactory( title=title, - parent=Site.objects.get(is_default_site=True).root_page, + parent=get_wagtail_default_site().root_page, course=course, ) course.slug = course_page.slug diff --git a/server/vbv_lernwelt/course/models.py b/server/vbv_lernwelt/course/models.py index 12721ca9..f5e77d67 100644 --- a/server/vbv_lernwelt/course/models.py +++ b/server/vbv_lernwelt/course/models.py @@ -2,7 +2,8 @@ import enum import uuid from django.db import models -from django.db.models import UniqueConstraint +from django.db.models import UniqueConstraint, Value +from django.db.models.functions import Replace from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from grapple.models import GraphQLString @@ -131,6 +132,30 @@ class CourseBasePage(Page): def __str__(self): return f"{self.title}" + def _update_descendant_slugs(self, old_slug, new_slug): + """ + this method is inspired by `_update_descendant_url_paths` from wagtail Page + """ + Page.objects.filter(path__startswith=self.path).exclude(pk=self.pk).update( + slug=Replace("slug", Value(old_slug), Value(new_slug)) + ) + + def save(self, clean=True, user=None, log_action=False, **kwargs): + slug_changed = False + + if not self.id is None: + old_record = Page.objects.get(id=self.id).specific + if old_record.slug != self.slug: + self.set_url_path(self.get_parent()) + slug_changed = True + old_slug = old_record.slug + new_slug = self.slug + + super().save(**kwargs) + + if slug_changed: + self._update_descendant_slugs(old_slug, new_slug) + class CoursePage(CourseBasePage): content_panels = Page.content_panels diff --git a/server/vbv_lernwelt/course/tests/test_model_save.py b/server/vbv_lernwelt/course/tests/test_model_save.py new file mode 100644 index 00000000..45710866 --- /dev/null +++ b/server/vbv_lernwelt/course/tests/test_model_save.py @@ -0,0 +1,38 @@ +from rest_framework.test import APITestCase + +from vbv_lernwelt.core.create_default_users import create_default_users +from vbv_lernwelt.course.creators.test_course import create_test_course +from vbv_lernwelt.learnpath.models import Circle, LearningContentAttendanceCourse + + +class CourseBasePageSaveTestCase(APITestCase): + def setUp(self) -> None: + create_default_users() + create_test_course() + + def test_save_willRenameSlugsOfChildren(self): + circle_fahrzeug = Circle.objects.get(title="Fahrzeug") + self.assertEqual(circle_fahrzeug.slug, "test-lehrgang-lp-circle-fahrzeug") + + lc_attendance_course = LearningContentAttendanceCourse.objects.descendant_of( + circle_fahrzeug + ).first() + self.assertEqual( + lc_attendance_course.slug, + "test-lehrgang-lp-circle-fahrzeug-lc-präsenzkurs-fahrzeug", + ) + + # title update should also update the slugs of the descendants + circle_fahrzeug.title = "Foobar" + circle_fahrzeug.save() + + circle_fahrzeug = Circle.objects.get(id=circle_fahrzeug.id) + self.assertEqual(circle_fahrzeug.slug, "test-lehrgang-lp-circle-foobar") + + lc_attendance_course = LearningContentAttendanceCourse.objects.descendant_of( + circle_fahrzeug + ).first() + self.assertEqual( + lc_attendance_course.slug, + "test-lehrgang-lp-circle-foobar-lc-präsenzkurs-fahrzeug", + ) diff --git a/server/vbv_lernwelt/course/utils.py b/server/vbv_lernwelt/course/utils.py new file mode 100644 index 00000000..57cb333a --- /dev/null +++ b/server/vbv_lernwelt/course/utils.py @@ -0,0 +1,15 @@ +import wagtail_factories +from django.conf import settings +from wagtail.models import Locale, Site + + +def get_wagtail_default_site(): + for language in settings.WAGTAIL_CONTENT_LANGUAGES: + Locale.objects.get_or_create(language_code=language[0]) + + site = Site.objects.filter(is_default_site=True).first() + + if not site: + site = wagtail_factories.SiteFactory(is_default_site=True) + + return site