From cbdbdba6b85d01e4a58f545c784d942e53ea715f Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 3 Oct 2022 17:40:35 +0200 Subject: [PATCH] Add `frontend_url` field to wagtail pages --- client/src/components/MainNavigationBar.vue | 2 +- .../learningPath/LearningPathDiagram.vue | 7 +- client/src/router/index.ts | 3 +- client/src/services/circle.ts | 10 +- client/src/services/learningPath.ts | 2 + client/src/stores/circle.ts | 10 +- client/src/types.ts | 1 + client/src/views/LearningPathView.vue | 9 +- .../media_library/MediaCategoryDetailView.vue | 4 +- .../MediaLibraryCategoryOverview.vue | 4 +- server/vbv_lernwelt/competence/models.py | 10 - server/vbv_lernwelt/course/views.py | 3 +- server/vbv_lernwelt/learnpath/models.py | 43 +- .../learnpath/serializer_helpers.py | 19 +- server/vbv_lernwelt/learnpath/serializers.py | 5 - .../create_default_media_library.py | 6 +- .../media_library/migrations/0001_initial.py | 408 ++++++++++++++++-- server/vbv_lernwelt/media_library/models.py | 19 +- .../tests/media_library_factories.py | 2 +- 19 files changed, 449 insertions(+), 118 deletions(-) diff --git a/client/src/components/MainNavigationBar.vue b/client/src/components/MainNavigationBar.vue index b30dc0cd..c6880623 100644 --- a/client/src/components/MainNavigationBar.vue +++ b/client/src/components/MainNavigationBar.vue @@ -170,7 +170,7 @@ const profileDropdownData = [ Shop diff --git a/client/src/components/learningPath/LearningPathDiagram.vue b/client/src/components/learningPath/LearningPathDiagram.vue index d7c3538d..43e923b7 100644 --- a/client/src/components/learningPath/LearningPathDiagram.vue +++ b/client/src/components/learningPath/LearningPathDiagram.vue @@ -67,10 +67,7 @@ export default { const newCircle = {}; newCircle.pieData = pieData.reverse(); newCircle.title = circle.title; - newCircle.slug = circle.slug.replace( - `${circle.parentLearningPath.slug}-circle-`, - "" - ); + newCircle.frontend_url = circle.frontend_url; newCircle.id = circle.id; internalCircles.push(newCircle); }); @@ -155,7 +152,7 @@ export default { }); }) .on("click", (d, i) => { - vueRouter.push(`/learn/${this.learningPathStore.learningPath.slug}/${i.slug}`); + vueRouter.push(i.frontend_url); }) .attr("role", "button"); diff --git a/client/src/router/index.ts b/client/src/router/index.ts index 980df22e..a7d7ab7c 100644 --- a/client/src/router/index.ts +++ b/client/src/router/index.ts @@ -40,7 +40,8 @@ const router = createRouter({ }, { path: "handlungsfelder", - component: () => import("@/views/media_library/MediaLibraryCategoryOverview.vue"), + component: () => + import("@/views/media_library/MediaLibraryCategoryOverview.vue"), }, { path: "handlungsfeldlist", diff --git a/client/src/services/circle.ts b/client/src/services/circle.ts index 002e4eea..4d69baa9 100644 --- a/client/src/services/circle.ts +++ b/client/src/services/circle.ts @@ -21,6 +21,7 @@ function _createEmptyLearningUnit( slug: "", translation_key: "", type: "learnpath.LearningUnit", + frontend_url: "", learningContents: [], minutes: 0, parentLearningSequence: parentLearningSequence, @@ -131,7 +132,8 @@ export class Circle implements CourseWagtailPage { public readonly slug: string, public readonly title: string, public readonly translation_key: string, - public description: string, + public readonly frontend_url: string, + public readonly description: string, public children: CircleChild[], public goals: CircleGoal[], public job_situations: CircleJobSituation[], @@ -147,6 +149,7 @@ export class Circle implements CourseWagtailPage { json.slug, json.title, json.translation_key, + json.frontend_url, json.description, json.children, json.goals, @@ -241,9 +244,4 @@ export class Circle implements CourseWagtailPage { this.parentLearningPath.calcNextLearningContent(completionData); } } - - public getUrl(): string { - const shortSlug = this.slug.replace(`${this.parentLearningPath?.slug}-circle-`, ""); - return `/learn/${this.parentLearningPath?.slug}/${shortSlug}`; - } } diff --git a/client/src/services/learningPath.ts b/client/src/services/learningPath.ts index e4890e5e..94a85cbc 100644 --- a/client/src/services/learningPath.ts +++ b/client/src/services/learningPath.ts @@ -35,6 +35,7 @@ export class LearningPath implements CourseWagtailPage { json.slug, json.title, json.translation_key, + json.frontend_url, json.course.id, json.children, completionData @@ -46,6 +47,7 @@ export class LearningPath implements CourseWagtailPage { public readonly slug: string, public readonly title: string, public readonly translation_key: string, + public readonly frontend_url: string, public readonly courseId: number, public children: LearningPathChild[], completionData?: CourseCompletion[] diff --git a/client/src/stores/circle.ts b/client/src/stores/circle.ts index 3fb432f6..11c729c1 100644 --- a/client/src/stores/circle.ts +++ b/client/src/stores/circle.ts @@ -94,25 +94,23 @@ export const useCircleStore = defineStore({ } }, openLearningContent(learningContent: LearningContent) { - const shortSlug = learningContent.slug.replace(`${this.circle?.slug}-lc-`, ""); this.router.push({ - path: `${this.circle?.getUrl()}/${shortSlug}`, + path: learningContent.frontend_url, }); }, closeLearningContent() { this.router.push({ - path: `${this.circle?.getUrl()}`, + path: `${this.circle?.frontend_url}`, }); }, openSelfEvaluation(learningUnit: LearningUnit) { - const shortSlug = learningUnit.slug.replace(`${this.circle?.slug}-lu-`, ""); this.router.push({ - path: `${this.circle?.getUrl()}/evaluate/${shortSlug}`, + path: learningUnit.frontend_url, }); }, closeSelfEvaluation() { this.router.push({ - path: `${this.circle?.getUrl()}`, + path: `${this.circle?.frontend_url}`, }); }, calcSelfEvaluationStatus(learningUnit: LearningUnit) { diff --git a/client/src/types.ts b/client/src/types.ts index 5a0a5ebb..45add270 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -119,6 +119,7 @@ export interface CourseWagtailPage { readonly title: string; readonly slug: string; readonly translation_key: string; + readonly frontend_url: string; completion_status: CourseCompletionStatus; } diff --git a/client/src/views/LearningPathView.vue b/client/src/views/LearningPathView.vue index 75e7d729..b2e0cc68 100644 --- a/client/src/views/LearningPathView.vue +++ b/client/src/views/LearningPathView.vue @@ -31,12 +31,9 @@ onMounted(async () => { const createContinueUrl = (learningPath: LearningPath): [string, boolean] => { if (learningPath.nextLearningContent) { const circle = learningPath.nextLearningContent.parentCircle; - const lsShortSlug = - learningPath.nextLearningContent.parentLearningSequence?.slug.replace( - `${circle.slug}-`, - "" - ); - const url = `/learn/${learningPath.slug}/${learningPath.nextLearningContent.parentCircle.slug}#${lsShortSlug}`; + const url = + learningPath.nextLearningContent.parentLearningSequence?.frontend_url || + circle.frontend_url; const isFirst = learningPath.nextLearningContent.translation_key === learningPath.circles[0].flatLearningContents[0].translation_key; diff --git a/client/src/views/media_library/MediaCategoryDetailView.vue b/client/src/views/media_library/MediaCategoryDetailView.vue index 7d2db8fe..fd7cfb44 100644 --- a/client/src/views/media_library/MediaCategoryDetailView.vue +++ b/client/src/views/media_library/MediaCategoryDetailView.vue @@ -166,8 +166,8 @@ log.debug("MediaCategoryDetailView created", props.mediaCategorySlug); const mediaStore = useMediaLibraryStore(); const mediaCategory = computed(() => { - return mediaStore.mediaLibraryPage?.children.find( - (category) => category.slug === props.mediaCategorySlug + return mediaStore.mediaLibraryPage?.children.find((category) => + category.slug.endsWith(props.mediaCategorySlug) ); }); diff --git a/client/src/views/media_library/MediaLibraryCategoryOverview.vue b/client/src/views/media_library/MediaLibraryCategoryOverview.vue index 98faba2a..81bc5bb0 100644 --- a/client/src/views/media_library/MediaLibraryCategoryOverview.vue +++ b/client/src/views/media_library/MediaLibraryCategoryOverview.vue @@ -28,9 +28,7 @@ watch(dropdownSelected, (newValue) => :key="cat.id" class="bg-white p-4" > - +

{{ cat.title }}

diff --git a/server/vbv_lernwelt/competence/models.py b/server/vbv_lernwelt/competence/models.py index 5286613e..e61a7d7c 100644 --- a/server/vbv_lernwelt/competence/models.py +++ b/server/vbv_lernwelt/competence/models.py @@ -28,11 +28,6 @@ class CompetenceProfilePage(Page): return get_it_serializer_class( cls, [ - "id", - "title", - "slug", - "type", - "translation_key", "course", "children", ], @@ -69,11 +64,6 @@ class CompetencePage(Page): return get_it_serializer_class( cls, [ - "id", - "title", - "slug", - "type", - "translation_key", "children", ], ) diff --git a/server/vbv_lernwelt/course/views.py b/server/vbv_lernwelt/course/views.py index 2a0ddace..bd480b6f 100644 --- a/server/vbv_lernwelt/course/views.py +++ b/server/vbv_lernwelt/course/views.py @@ -1,4 +1,5 @@ import structlog +from django.views.decorators.cache import cache_page from rest_framework.decorators import api_view from rest_framework.response import Response from wagtail.models import Page @@ -11,7 +12,7 @@ logger = structlog.get_logger(__name__) @api_view(["GET"]) -# @cache_page(60 * 60 * 8, cache="api_page_cache") +@cache_page(60 * 60 * 8, cache="api_page_cache") def page_api_view(request, slug): try: page = Page.objects.get(slug=slug, locale__language_code="de-CH") diff --git a/server/vbv_lernwelt/learnpath/models.py b/server/vbv_lernwelt/learnpath/models.py index ac9e50fa..ac861d1c 100644 --- a/server/vbv_lernwelt/learnpath/models.py +++ b/server/vbv_lernwelt/learnpath/models.py @@ -40,11 +40,17 @@ class LearningPath(Page): def __str__(self): return f"{self.title}" + def get_frontend_url(self): + return f"/learn/{self.slug}" + @classmethod def get_serializer_class(cls): return get_it_serializer_class( cls, - ["id", "title", "slug", "type", "translation_key", "children", "course"], + [ + "children", + "course", + ], ) @@ -76,11 +82,6 @@ class Topic(Page): return get_it_serializer_class( cls, field_names=[ - "id", - "title", - "slug", - "type", - "translation_key", "is_visible", ], ) @@ -143,11 +144,6 @@ class Circle(Page): return get_it_serializer_class( cls, field_names=[ - "id", - "title", - "slug", - "type", - "translation_key", "children", "description", "job_situations", @@ -156,6 +152,10 @@ class Circle(Page): ], ) + def get_frontend_url(self): + short_slug = self.slug.replace(f"{self.get_parent().slug}-circle-", "") + return f"{self.get_parent().specific.get_frontend_url()}/{short_slug}" + def full_clean(self, *args, **kwargs): self.slug = find_slug_with_parent_prefix(self, "circle") super(Circle, self).full_clean(*args, **kwargs) @@ -185,9 +185,7 @@ class LearningSequence(Page): @classmethod def get_serializer_class(cls): - return get_it_serializer_class( - cls, field_names=["id", "title", "slug", "type", "translation_key", "icon"] - ) + return get_it_serializer_class(cls, field_names=["icon"]) def get_admin_display_title(self): return f"{self.icon} {self.draft_title}" @@ -203,6 +201,10 @@ class LearningSequence(Page): self.slug = find_slug_with_parent_prefix(self, "ls") super(LearningSequence, self).full_clean(*args, **kwargs) + def get_frontend_url(self): + short_slug = self.slug.replace(f"{self.get_parent().slug}-", "") + return f"{self.get_parent().specific.get_frontend_url()}#{short_slug}" + class LearningUnit(Page): parent_page_types = ["learnpath.Circle"] @@ -240,6 +242,10 @@ class LearningUnit(Page): ) super(LearningUnit, self).full_clean(*args, **kwargs) + def get_frontend_url(self): + short_slug = self.slug.replace(f"{self.get_parent().slug}-lu-", "") + return f"{self.get_parent().specific.get_frontend_url()}/evaluate/{short_slug}" + @classmethod def get_serializer_class(cls): from vbv_lernwelt.learnpath.serializers import LearningUnitSerializer @@ -298,6 +304,10 @@ class LearningContent(Page): class Meta: verbose_name = "Learning Content" + def get_frontend_url(self): + short_slug = self.slug.replace(f"{self.get_parent().slug}-lc-", "") + return f"{self.get_parent().specific.get_frontend_url()}/{short_slug}" + def full_clean(self, *args, **kwargs): self.slug = find_slug_with_parent_prefix(self, "lc") super(LearningContent, self).full_clean(*args, **kwargs) @@ -307,11 +317,6 @@ class LearningContent(Page): return get_it_serializer_class( cls, field_names=[ - "id", - "title", - "slug", - "type", - "translation_key", "minutes", "contents", ], diff --git a/server/vbv_lernwelt/learnpath/serializer_helpers.py b/server/vbv_lernwelt/learnpath/serializer_helpers.py index e59b644d..57c385f8 100644 --- a/server/vbv_lernwelt/learnpath/serializer_helpers.py +++ b/server/vbv_lernwelt/learnpath/serializer_helpers.py @@ -7,8 +7,19 @@ from vbv_lernwelt.learnpath.utils import get_wagtail_type def get_it_serializer_class(model, field_names): + base_field_names = [ + "id", + "title", + "slug", + "type", + "translation_key", + "frontend_url", + ] return wagtail_serializers.get_serializer_class( - model, field_names=field_names, meta_fields=[], base=ItBaseSerializer + model, + field_names=base_field_names + field_names, + meta_fields=[], + base=ItBaseSerializer, ) @@ -23,6 +34,7 @@ class ItBaseSerializer(wagtail_serializers.BaseSerializer): children = SerializerMethodField() course = SerializerMethodField() course_category = CourseCategorySerializer(read_only=True) + frontend_url = SerializerMethodField() meta_fields = [] @@ -50,6 +62,11 @@ class ItBaseSerializer(wagtail_serializers.BaseSerializer): return CourseSerializer(course_parent_page.specific.course).data return "" + def get_frontend_url(self, obj): + if hasattr(obj, "get_frontend_url"): + return obj.get_frontend_url() + return "" + def _get_descendants(pages, obj): return [c for c in pages if c.path.startswith(obj.path) and c.depth >= obj.depth] diff --git a/server/vbv_lernwelt/learnpath/serializers.py b/server/vbv_lernwelt/learnpath/serializers.py index 58eb2673..57f1195e 100644 --- a/server/vbv_lernwelt/learnpath/serializers.py +++ b/server/vbv_lernwelt/learnpath/serializers.py @@ -9,11 +9,6 @@ class LearningUnitSerializer( get_it_serializer_class( LearningUnit, [ - "id", - "title", - "slug", - "type", - "translation_key", "course_category", "children", ], diff --git a/server/vbv_lernwelt/media_library/create_default_media_library.py b/server/vbv_lernwelt/media_library/create_default_media_library.py index dc672a30..2ffd1324 100644 --- a/server/vbv_lernwelt/media_library/create_default_media_library.py +++ b/server/vbv_lernwelt/media_library/create_default_media_library.py @@ -4,15 +4,15 @@ from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN_ID from vbv_lernwelt.course.models import Course, CoursePage from vbv_lernwelt.media_library.tests.media_library_factories import ( create_external_link_block, + create_internal_link_block, create_learn_media_block, create_media_collection, + create_relative_link_block, ExternalLinkBlockFactory, + InternalLinkBlockFactory, LearnMediaBlockFactory, MediaCategoryPageFactory, MediaLibraryPageFactory, - create_internal_link_block, - InternalLinkBlockFactory, - create_relative_link_block, RelativeLinkBlockFactory, ) diff --git a/server/vbv_lernwelt/media_library/migrations/0001_initial.py b/server/vbv_lernwelt/media_library/migrations/0001_initial.py index 1cf58ff9..8ae8eef6 100644 --- a/server/vbv_lernwelt/media_library/migrations/0001_initial.py +++ b/server/vbv_lernwelt/media_library/migrations/0001_initial.py @@ -1,13 +1,13 @@ # Generated by Django 3.2.13 on 2022-10-03 14:18 -from django.conf import settings -from django.db import migrations, models import django.db.models.deletion import taggit.managers import wagtail.blocks import wagtail.fields import wagtail.models.collections import wagtail.search.index +from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): @@ -15,61 +15,395 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('course', '0001_initial'), + ("course", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'), - ('wagtailcore', '0069_log_entry_jsonfield'), + ("taggit", "0004_alter_taggeditem_content_type_alter_taggeditem_tag"), + ("wagtailcore", "0069_log_entry_jsonfield"), ] operations = [ migrations.CreateModel( - name='MediaLibraryPage', + name="MediaLibraryPage", fields=[ - ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ( + "page_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailcore.page", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('wagtailcore.page',), + bases=("wagtailcore.page",), ), migrations.CreateModel( - name='MediaCategoryPage', + name="MediaCategoryPage", fields=[ - ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), - ('introduction_text', models.TextField(default='')), - ('description_title', models.TextField(default='Das erwartet dich in diesem Handlungsfeld')), - ('description_text', models.TextField(default='')), - ('items', wagtail.fields.StreamField([('item', wagtail.blocks.TextBlock())], use_json_field=True)), - ('overview_icon', models.CharField(default='icon-hf-fahrzeug', max_length=255)), - ('body', wagtail.fields.StreamField([('content_collection', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('contents', wagtail.blocks.StreamBlock([('learn_media', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='', required=False)), ('icon_url', wagtail.blocks.TextBlock(default='', required=False)), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.TextBlock(default='', required=False)), ('open_window', wagtail.blocks.BooleanBlock(default=False)), ('page', wagtail.blocks.PageChooserBlock(page_type=['learnpath.LearningContent'], required=False))])), ('external_link', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='', required=False)), ('icon_url', wagtail.blocks.TextBlock(default='', required=False)), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.TextBlock(default='', required=False)), ('open_window', wagtail.blocks.BooleanBlock(default=False)), ('page', wagtail.blocks.PageChooserBlock(page_type=['learnpath.LearningContent'], required=False))])), ('internal_link', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='', required=False)), ('icon_url', wagtail.blocks.TextBlock(default='', required=False)), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.TextBlock(default='', required=False)), ('open_window', wagtail.blocks.BooleanBlock(default=False)), ('page', wagtail.blocks.PageChooserBlock(page_type=['learnpath.LearningContent'], required=False))])), ('relative_link', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='', required=False)), ('icon_url', wagtail.blocks.TextBlock(default='', required=False)), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.TextBlock(default='', required=False)), ('open_window', wagtail.blocks.BooleanBlock(default=False)), ('page', wagtail.blocks.PageChooserBlock(page_type=['learnpath.LearningContent'], required=False))]))]))]))], null=True, use_json_field=True)), - ('course_category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='course.coursecategory')), + ( + "page_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailcore.page", + ), + ), + ("introduction_text", models.TextField(default="")), + ( + "description_title", + models.TextField( + default="Das erwartet dich in diesem Handlungsfeld" + ), + ), + ("description_text", models.TextField(default="")), + ( + "items", + wagtail.fields.StreamField( + [("item", wagtail.blocks.TextBlock())], use_json_field=True + ), + ), + ( + "overview_icon", + models.CharField(default="icon-hf-fahrzeug", max_length=255), + ), + ( + "body", + wagtail.fields.StreamField( + [ + ( + "content_collection", + wagtail.blocks.StructBlock( + [ + ("title", wagtail.blocks.TextBlock()), + ( + "contents", + wagtail.blocks.StreamBlock( + [ + ( + "learn_media", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.TextBlock( + blank=False, + null=False, + ), + ), + ( + "description", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "icon_url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "link_display_text", + wagtail.blocks.CharBlock( + default="Link öffnen", + max_length=255, + ), + ), + ( + "url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "open_window", + wagtail.blocks.BooleanBlock( + default=False + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + page_type=[ + "learnpath.LearningContent" + ], + required=False, + ), + ), + ] + ), + ), + ( + "external_link", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.TextBlock( + blank=False, + null=False, + ), + ), + ( + "description", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "icon_url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "link_display_text", + wagtail.blocks.CharBlock( + default="Link öffnen", + max_length=255, + ), + ), + ( + "url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "open_window", + wagtail.blocks.BooleanBlock( + default=False + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + page_type=[ + "learnpath.LearningContent" + ], + required=False, + ), + ), + ] + ), + ), + ( + "internal_link", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.TextBlock( + blank=False, + null=False, + ), + ), + ( + "description", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "icon_url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "link_display_text", + wagtail.blocks.CharBlock( + default="Link öffnen", + max_length=255, + ), + ), + ( + "url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "open_window", + wagtail.blocks.BooleanBlock( + default=False + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + page_type=[ + "learnpath.LearningContent" + ], + required=False, + ), + ), + ] + ), + ), + ( + "relative_link", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.TextBlock( + blank=False, + null=False, + ), + ), + ( + "description", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "icon_url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "link_display_text", + wagtail.blocks.CharBlock( + default="Link öffnen", + max_length=255, + ), + ), + ( + "url", + wagtail.blocks.TextBlock( + default="", + required=False, + ), + ), + ( + "open_window", + wagtail.blocks.BooleanBlock( + default=False + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + page_type=[ + "learnpath.LearningContent" + ], + required=False, + ), + ), + ] + ), + ), + ] + ), + ), + ] + ), + ) + ], + null=True, + use_json_field=True, + ), + ), + ( + "course_category", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="course.coursecategory", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('wagtailcore.page',), + bases=("wagtailcore.page",), ), migrations.CreateModel( - name='LibraryDocument', + name="LibraryDocument", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=255, verbose_name='title')), - ('file', models.FileField(upload_to='documents', verbose_name='file')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('file_size', models.PositiveIntegerField(editable=False, null=True)), - ('file_hash', models.CharField(blank=True, editable=False, max_length=40)), - ('display_text', models.CharField(default='', max_length=1024)), - ('description', models.TextField(default='')), - ('link_display_text', models.CharField(default='', max_length=1024)), - ('thumbnail', models.URLField()), - ('collection', models.ForeignKey(default=wagtail.models.collections.get_root_collection_id, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.collection', verbose_name='collection')), - ('tags', taggit.managers.TaggableManager(blank=True, help_text=None, through='taggit.TaggedItem', to='taggit.Tag', verbose_name='tags')), - ('uploaded_by_user', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded by user')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=255, verbose_name="title")), + ("file", models.FileField(upload_to="documents", verbose_name="file")), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ("file_size", models.PositiveIntegerField(editable=False, null=True)), + ( + "file_hash", + models.CharField(blank=True, editable=False, max_length=40), + ), + ("display_text", models.CharField(default="", max_length=1024)), + ("description", models.TextField(default="")), + ("link_display_text", models.CharField(default="", max_length=1024)), + ("thumbnail", models.URLField()), + ( + "collection", + models.ForeignKey( + default=wagtail.models.collections.get_root_collection_id, + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="wagtailcore.collection", + verbose_name="collection", + ), + ), + ( + "tags", + taggit.managers.TaggableManager( + blank=True, + help_text=None, + through="taggit.TaggedItem", + to="taggit.Tag", + verbose_name="tags", + ), + ), + ( + "uploaded_by_user", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + verbose_name="uploaded by user", + ), + ), ], options={ - 'verbose_name': 'document', - 'verbose_name_plural': 'documents', - 'abstract': False, + "verbose_name": "document", + "verbose_name_plural": "documents", + "abstract": False, }, bases=(wagtail.search.index.Indexed, models.Model), ), diff --git a/server/vbv_lernwelt/media_library/models.py b/server/vbv_lernwelt/media_library/models.py index 47e6f02f..7fac08d7 100644 --- a/server/vbv_lernwelt/media_library/models.py +++ b/server/vbv_lernwelt/media_library/models.py @@ -25,16 +25,14 @@ class MediaLibraryPage(Page): ) super(MediaLibraryPage, self).full_clean(*args, **kwargs) + def get_frontend_url(self): + return f"/media/{self.slug}" + @classmethod def get_serializer_class(cls): return get_it_serializer_class( cls, [ - "id", - "title", - "slug", - "type", - "translation_key", "course", "children", ], @@ -82,20 +80,19 @@ class MediaCategoryPage(Page): def full_clean(self, *args, **kwargs): self.slug = find_available_slug( - slugify(f"{self.get_parent()}-cat-{self.title}", allow_unicode=True) + slugify(f"{self.get_parent().slug}-cat-{self.title}", allow_unicode=True) ) super(MediaCategoryPage, self).full_clean(*args, **kwargs) + def get_frontend_url(self): + short_slug = self.slug.replace(f"{self.get_parent().slug}-cat-", "") + return f"{self.get_parent().specific.get_frontend_url()}/handlungsfelder/{short_slug}" + @classmethod def get_serializer_class(cls): return get_it_serializer_class( cls, field_names=[ - "id", - "title", - "slug", - "type", - "translation_key", "course_category", "introduction_text", "overview_icon", diff --git a/server/vbv_lernwelt/media_library/tests/media_library_factories.py b/server/vbv_lernwelt/media_library/tests/media_library_factories.py index 34861664..7a98a542 100644 --- a/server/vbv_lernwelt/media_library/tests/media_library_factories.py +++ b/server/vbv_lernwelt/media_library/tests/media_library_factories.py @@ -4,8 +4,8 @@ import wagtail_factories from vbv_lernwelt.media_library.content_blocks import ( ExternalLinkBlock, - LearnMediaBlock, InternalLinkBlock, + LearnMediaBlock, RelativeLinkBlock, ) from vbv_lernwelt.media_library.models import (