Adapt LearningPath to new course model

This commit is contained in:
Daniel Egger 2022-09-19 17:11:39 +02:00
parent ee4f6fb565
commit f9c3e82b66
15 changed files with 127 additions and 129 deletions

View File

@ -16,7 +16,7 @@ const userStore = useUserStore()
<div class="mt-8 p-8 break-words bg-white max-w-xl">
<h3>Versicherungsvermittler/in</h3>
<div class="mt-4">
<router-link class="btn-blue" to="/learn/versicherungsvermittlerin"> Weiter geht's </router-link>
<router-link class="btn-blue" to="/learn/versicherungsvermittlerin-lp"> Weiter geht's </router-link>
</div>
</div>
</main>

View File

@ -63,8 +63,8 @@ if [ "$SKIP_SETUP" = false ]; then
python3 server/manage.py migrate --settings="$DJANGO_SETTINGS_MODULE"
python3 server/manage.py create_default_users --settings="$DJANGO_SETTINGS_MODULE"
python3 server/manage.py create_default_courses --settings="$DJANGO_SETTINGS_MODULE"
# python3 server/manage.py create_default_learning_path --settings="$DJANGO_SETTINGS_MODULE"
# python3 server/manage.py create_default_media_library --settings="$DJANGO_SETTINGS_MODULE"
python3 server/manage.py create_default_learning_path --settings="$DJANGO_SETTINGS_MODULE"
python3 server/manage.py create_default_media_library --settings="$DJANGO_SETTINGS_MODULE"
# make django translations
(cd server && python3 manage.py compilemessages --settings="$DJANGO_SETTINGS_MODULE")

View File

@ -13,6 +13,9 @@ class Course(models.Model):
class Meta:
verbose_name = _("Lerngang")
def __str__(self):
return f"{self.name}"
class CourseCategory(models.Model):
# Die Handlungsfelder im "Versicherungsvermittler/in"
@ -20,10 +23,13 @@ class CourseCategory(models.Model):
course = models.ForeignKey('course.Course', on_delete=models.CASCADE)
general = models.BooleanField(_('Allgemein'), default=False)
def __str__(self):
return f"{self.course} / {self.name}"
class CoursePage(Page):
content_panels = Page.content_panels
subpage_types = ['learnpath.LearningPath', 'media_library.MediaLibrary']
subpage_types = ['learnpath.LearningPath', 'media_library.MediaLibraryPage']
course = models.ForeignKey('course.Course', on_delete=models.CASCADE)
class Meta:

View File

@ -5,6 +5,8 @@ from wagtail.models import Site, Page, Locale
from wagtail_localize.models import LocaleSynchronization
from vbv_lernwelt.core.admin import User
from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningContent, LearningUnit, \
LearningUnitQuestion
from vbv_lernwelt.learnpath.tests.learning_path_factories import LearningPathFactory, TopicFactory, CircleFactory, \
@ -340,7 +342,11 @@ def create_default_learning_path(user=None, skip_locales=True):
# create_default_competences()
lp = LearningPathFactory(title="Versicherungsvermittler/in", parent=site.root_page)
course_page = CoursePage.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN)
lp = LearningPathFactory(
title="Lernpfad",
parent=course_page,
)
TopicFactory(title="Basis", is_visible=False, parent=lp)

View File

@ -1,10 +1,10 @@
import djclick as click
from vbv_lernwelt.learnpath.create_default_learning_path import create_default_learning_path
from vbv_lernwelt.learnpath.tests.create_simple_test_learning_path import create_simple_test_learning_path
@click.command()
def command():
create_default_learning_path(skip_locales=True)
create_simple_test_learning_path(skip_locales=True)
# FIXME: readd
# create_simple_test_learning_path(skip_locales=True)

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-09-19 14:37
# Generated by Django 3.2.13 on 2022-09-19 15:05
from django.db import migrations, models
import django.db.models.deletion

View File

@ -17,13 +17,14 @@ class LearningPath(Page):
# PageChooserPanel('related_page', 'demo.PublisherPage'),
content_panels = Page.content_panels
subpage_types = ['learnpath.Circle', 'learnpath.Topic', 'media_library.MediaLibrary']
subpage_types = ['learnpath.Circle', 'learnpath.Topic']
parent_page_types = ['course.CoursePage']
class Meta:
verbose_name = "Learning Path"
def full_clean(self, *args, **kwargs):
self.slug = find_available_slug(slugify(self.title, allow_unicode=True))
self.slug = find_available_slug(slugify(f"{self.get_parent().slug}-lp", allow_unicode=True))
super(LearningPath, self).full_clean(*args, **kwargs)
def __str__(self):

View File

@ -32,7 +32,7 @@ class MediaLibraryContent(models.Model):
return self._revisions
class AnkerBlock(blocks.PageChooserBlock):
class AnchorBlock(blocks.PageChooserBlock):
"""
Verankerung im Lernpfad. Link to a Learning Content.
"""
@ -50,7 +50,7 @@ class CrossReferenceBlock(blocks.StructBlock):
title = models.TextField(blank=False, null=False)
description = blocks.TextBlock(default='')
link_display_text = blocks.CharBlock(max_length=255, default='Link öffnen')
category = blocks.PageChooserBlock(page_type='media_library.Category')
category = blocks.PageChooserBlock(page_type='media_library.MediaCategoryPage')
class ContentCollection(blocks.StructBlock):
@ -58,14 +58,17 @@ class ContentCollection(blocks.StructBlock):
Lernmedien, Links, Querverweise, Verankerung
"""
title = blocks.TextBlock()
collection_type = blocks.MultipleChoiceBlock(choices=VisualisationType.choices,
max_length=20,
default=VisualisationType.LEARNING_MEDIA)
contents = blocks.StreamBlock([('Links', LinkBlock()),
('Documents', DocumentChooserBlock()),
('Ankers', AnkerBlock()),
('CrossReference', CrossReferenceBlock())
])
collection_type = blocks.MultipleChoiceBlock(
choices=VisualisationType.choices,
max_length=20,
default=VisualisationType.LEARNING_MEDIA
)
contents = blocks.StreamBlock([
('Links', LinkBlock()),
('Documents', DocumentChooserBlock()),
('Ankers', AnchorBlock()),
('CrossReference', CrossReferenceBlock())
])
class Meta:
icon = 'link'

View File

@ -3,6 +3,7 @@ import os
import factory
from wagtail.core.models import Collection
from vbv_lernwelt.course.models import Course
from vbv_lernwelt.media_library.models import LibraryDocument
from vbv_lernwelt.media_library.tests.media_library_factories import LibraryDocumentFactory
@ -11,15 +12,11 @@ def create_default_collections():
c = Collection.objects.all().delete()
root, created = Collection.objects.get_or_create(name='Root', depth=0)
versicherungsvermittler = root.add_child(name='Versicherungsvermittler/in')
handlungsfelder = versicherungsvermittler.add_child(name='Handlungsfelder')
handlungsfelder_names = ['Fahrzeug', 'Reisen', 'Einkommensicherung', 'Gesundheit', 'Haushalt', 'Sparen',
'Pensionierung', 'KMU', 'Wohneigentum', 'Rechtsstreitigkeiten', 'Erben / Vererben',
'Selbständigkeit']
for handlungsfeld in handlungsfelder_names:
versicherungsvermittler = handlungsfelder.add_child(name=handlungsfeld)
for course in Course.objects.all():
course_collection = root.add_child(name=course.name)
for cat in course.coursecategory_set.all():
cat_collection = course_collection.add_child(name=cat.name)
def create_default_documents():
@ -48,5 +45,3 @@ def create_default_documents():
file=factory.django.FileField(from_path=os.path.join(path, filename), filename=filename),
collection=collection
)
pass

View File

@ -1,27 +1,32 @@
import json
from vbv_lernwelt.learnpath.models import LearningPath
from vbv_lernwelt.media_library.tests.media_library_factories import MediaLibraryFactory, TopCategoryFactory, \
CategoryFactory, collection_body_dict
from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN
from vbv_lernwelt.course.models import CoursePage, Course
from vbv_lernwelt.media_library.tests.media_library_factories import MediaLibraryPageFactory, MediaCategoryPageFactory, \
collection_body_dict
def create_default_media_library():
lp = LearningPath.objects.all().first()
course = Course.objects.get(id=COURSE_VERSICHERUNGSVERMITTLERIN)
course_page = CoursePage.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN)
m = MediaLibraryFactory(title='Mediathek', parent=lp)
media_lib_page = MediaLibraryPageFactory(
title='Mediathek',
parent=course_page,
)
top_cat = TopCategoryFactory(title='Handlungsfelder', parent=m)
handlungsfelder = ['Fahrzeug', 'Reisen', 'Einkommenssicherung', 'Gesundheit', 'Haushalt', 'Sparen', 'Pensionierung',
'KMU', 'Wohneigentum', 'Rechtsstreitigkeiten', 'Erben / Vererben', 'Selbständigkeit']
for title in handlungsfelder:
introduction_text = 'Das Auto ist für viele der grösste Stolz! Es birgt aber auch ein grosses Gefahrenpotenzial. Dabei geht es bei den heutigen Fahrzeugpreisen und Reparaturkosten rasch um namhafte Summen, die der Fahrzeugbesitzer und die Fahrzeugbesitzerin in einem grösseren Schadenfall oft nur schwer selbst aufbringen kann. '
description = ' Supi'
category = CategoryFactory(title=title,
parent=top_cat,
introduction_text=introduction_text,
description=description,
body=json.dumps(collection_body_dict()))
top_cat = TopCategoryFactory(title='Lernmedien', parent=m)
for cat in course.coursecategory_set.all():
introduction_text = '''
Das Auto ist für viele der grösste Stolz! Es birgt aber auch ein grosses Gefahrenpotenzial.
Dabei geht es bei den heutigen Fahrzeugpreisen und Reparaturkosten rasch um namhafte Summen,
die der Fahrzeugbesitzer und die Fahrzeugbesitzerin in einem grösseren Schadenfall oft nur schwer selbst aufbringen kann.
'''.strip()
description = 'Supi'
media_category = MediaCategoryPageFactory(
title=cat.name,
course_category=cat,
parent=media_lib_page,
introduction_text=introduction_text,
description=description,
body=json.dumps(collection_body_dict())
)

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-09-19 14:37
# Generated by Django 3.2.13 on 2022-09-19 15:57
from django.conf import settings
from django.db import migrations, models
@ -17,35 +17,13 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
('course', '0001_initial'),
('wagtailcore', '0069_log_entry_jsonfield'),
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Category',
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', wagtail.fields.RichTextField(default='')),
('body', wagtail.fields.StreamField([('content_collection', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('collection_type', wagtail.blocks.MultipleChoiceBlock(choices=[('LearningMedia', 'Lernmedien'), ('Link', 'Links'), ('Anker', 'Verankerung'), ('CrossReference', 'Querverweise')], max_length=20)), ('contents', wagtail.blocks.StreamBlock([('Links', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='')), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.URLBlock())])), ('Documents', wagtail.documents.blocks.DocumentChooserBlock()), ('Ankers', vbv_lernwelt.media_library.content_blocks.AnkerBlock()), ('CrossReference', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock(default='')), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('category', wagtail.blocks.PageChooserBlock(page_type=['media_library.Category']))]))]))]))], null=True, use_json_field=True)),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='MediaLibrary',
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')),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='MediaLibraryContent',
fields=[
@ -56,7 +34,7 @@ class Migration(migrations.Migration):
],
),
migrations.CreateModel(
name='TopCategory',
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')),
],
@ -65,6 +43,20 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
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', wagtail.fields.RichTextField(default='')),
('body', wagtail.fields.StreamField([('content_collection', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('collection_type', wagtail.blocks.MultipleChoiceBlock(choices=[('LearningMedia', 'Lernmedien'), ('Link', 'Links'), ('Anker', 'Verankerung'), ('CrossReference', 'Querverweise')], max_length=20)), ('contents', wagtail.blocks.StreamBlock([('Links', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='')), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.URLBlock())])), ('Documents', wagtail.documents.blocks.DocumentChooserBlock()), ('Ankers', vbv_lernwelt.media_library.content_blocks.AnchorBlock()), ('CrossReference', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock(default='')), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('category', wagtail.blocks.PageChooserBlock(page_type=['media_library.MediaCategoryPage']))]))]))]))], null=True, use_json_field=True)),
('course_category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.coursecategory')),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='LibraryDocument',
fields=[

View File

@ -1,53 +1,55 @@
from django.db import models
from django.utils.text import slugify
from wagtail import fields
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
from wagtail.documents.models import AbstractDocument, Document
# Create your models here.
from wagtail.models import Page
from vbv_lernwelt.core.model_utils import find_available_slug
from vbv_lernwelt.media_library.content_blocks import ContentCollection
class MediaLibrary(Page):
parent_page_types = ['learnpath.LearningPath']
subpage_types = ['media_library.TopCategory']
class MediaLibraryPage(Page):
parent_page_types = ['course.CoursePage']
subpage_types = ['media_library.MediaCategoryPage']
content_panels = [
FieldPanel('title', classname="full title"),
]
class TopCategory(Page):
"""
Handlungsfelder
"""
parent_page_types = ['media_library.MediaLibrary']
subpage_types = ['media_library.Category']
content_panels = [
FieldPanel('title', classname="full title"),
]
def full_clean(self, *args, **kwargs):
self.slug = find_available_slug(slugify(f"{self.get_parent().slug}-media", allow_unicode=True))
super(MediaLibraryPage, self).full_clean(*args, **kwargs)
# Todo: use wagtail collections for this... Only applicable for documents, since links etc. dont have collections
class Category(Page):
class MediaCategoryPage(Page):
"""
Handlungsfeld. zB. Fahrzeug
"""
parent_page_types = ['media_library.TopCategory']
course_category = models.ForeignKey('course.CourseCategory', on_delete=models.CASCADE)
parent_page_types = ['media_library.MediaLibraryPage']
introduction_text = models.TextField(default='')
description = fields.RichTextField(default='')
body = fields.StreamField([('content_collection', ContentCollection())
], use_json_field=True, null=True)
body = fields.StreamField(
[('content_collection', ContentCollection())],
use_json_field=True,
null=True
)
content_panels = [
FieldPanel('title', classname="full title"),
FieldPanel('course_category'),
FieldPanel('introduction_text', classname="introduction text"),
FieldPanel('description', classname="introduction text"),
StreamFieldPanel('body')
]
def full_clean(self, *args, **kwargs):
self.slug = find_available_slug(slugify(f"{self.get_parent()}-cat-{self.title}", allow_unicode=True))
super(MediaCategoryPage, self).full_clean(*args, **kwargs)
class LibraryDocument(AbstractDocument):
# Todo: check https://filepreviews.io/

View File

@ -1,11 +1,9 @@
import json
import wagtail_factories
import factory
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningContent, LearningUnit, \
LearningUnitQuestion
from vbv_lernwelt.media_library.models import LibraryDocument, MediaLibrary, TopCategory, Category
from vbv_lernwelt.media_library.content_blocks import ContentCollection, AnkerBlock, LinkBlock, CrossReferenceBlock
from vbv_lernwelt.media_library.content_blocks import ContentCollection, AnchorBlock, LinkBlock, CrossReferenceBlock
from vbv_lernwelt.media_library.models import LibraryDocument, MediaLibraryPage, MediaCategoryPage
class LibraryDocumentFactory(wagtail_factories.DocumentFactory):
@ -16,23 +14,16 @@ class LibraryDocumentFactory(wagtail_factories.DocumentFactory):
model = LibraryDocument
class MediaLibraryFactory(wagtail_factories.PageFactory):
class MediaLibraryPageFactory(wagtail_factories.PageFactory):
title = 'Mediathek'
class Meta:
model = MediaLibrary
model = MediaLibraryPage
class TopCategoryFactory(wagtail_factories.PageFactory):
title = 'Handlungsfelder'
class AnchorBlockFactory(wagtail_factories.StructBlockFactory):
class Meta:
model = TopCategory
class AnkerBlockFactory(wagtail_factories.StructBlockFactory):
class Meta:
model = AnkerBlock
model = AnchorBlock
class LinkBlockFactory(wagtail_factories.StructBlockFactory):
@ -60,18 +51,18 @@ class ContentCollectionFactory(wagtail_factories.StructBlockFactory):
model = ContentCollection
class CategoryFactory(wagtail_factories.PageFactory):
class MediaCategoryPageFactory(wagtail_factories.PageFactory):
title = 'Fahrzeug'
introduction_text = 'Das Auto ist für viele der grösste Stolz! Es birgt aber ...'
description = 'Das erwartet dich in diesem Handlungsfeld'
body = wagtail_factories.StreamFieldFactory({'contents': ContentCollectionFactory})
class Meta:
model = Category
model = MediaCategoryPage
def generate_default_category():
category = CategoryFactory()
category = MediaCategoryPageFactory()
category.body = json.dumps(collection_body_dict())
category.save()
return category

View File

@ -1,13 +1,11 @@
from django.test import TestCase
from wagtail.core.models import Collection
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.tests.helpers import create_locales_for_wagtail
from vbv_lernwelt.media_library.create_default_documents import create_default_collections, create_default_documents
from vbv_lernwelt.media_library.create_default_media_library import create_default_media_library
from vbv_lernwelt.media_library.models import LibraryDocument
from vbv_lernwelt.learnpath.tests.learning_path_factories import LearningPathFactory
from vbv_lernwelt.media_library.models import MediaLibrary, TopCategory, Category
from vbv_lernwelt.media_library.create_default_media_library import create_default_media_library
from vbv_lernwelt.media_library.models import MediaLibraryPage, MediaCategoryPage
class TestCreateDefaultDocuments(TestCase):
def setUp(self) -> None:
@ -19,12 +17,11 @@ class TestCreateDefaultDocuments(TestCase):
def test_create_default_media_library(self):
self.assertEqual(MediaLibrary.objects.all().count(), 1)
self.assertEqual(TopCategory.objects.all().count(), 2)
self.assertEqual(Category.objects.all().count(), 12)
self.assertEqual(MediaLibraryPage.objects.all().count(), 1)
self.assertEqual(MediaCategoryPage.objects.all().count(), 12)
def test_create_category_fahrzeug_contains_content(self):
fahrzeug = Category.objects.get(title='Fahrzeug')
fahrzeug = MediaCategoryPage.objects.get(title='Fahrzeug')

View File

@ -6,8 +6,8 @@ from wagtail.core.models import Collection
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.tests.helpers import create_locales_for_wagtail
from vbv_lernwelt.media_library.create_default_documents import create_default_collections, create_default_documents
from vbv_lernwelt.media_library.models import LibraryDocument, Category
from vbv_lernwelt.media_library.tests.media_library_factories import ContentCollectionFactory, CategoryFactory, \
from vbv_lernwelt.media_library.models import LibraryDocument, MediaCategoryPage
from vbv_lernwelt.media_library.tests.media_library_factories import ContentCollectionFactory, MediaCategoryPageFactory, \
LinkBlockFactory, generate_default_category, generate_default_content2, collection_body_dict
@ -32,16 +32,16 @@ class TestMediaLibraryFactories(TestCase):
default_content = generate_default_content2()
default_content['body__content_collection__0__title'] = 'Spidf'
category = CategoryFactory(**default_content)
category = MediaCategoryPageFactory(**default_content)
print(category.body.raw_data)
self.assertNotEqual(category.body.raw_data, [])
def collection_via_dict_generation(self):
category = CategoryFactory()
category = MediaCategoryPageFactory()
category.body = json.dumps(collection_body_dict())
category.save()
category_id = category.id
new_category = Category.objects.get(id=category_id)
new_category = MediaCategoryPage.objects.get(id=category_id)
self.assertNotEqual(new_category.body, [])
self.assertNotEqual(new_category.body, [])