Squashed commit of feature/Mediathek from Renzo

commit ac0707296df479c0de5399b8adcccc24da749810
Author: Lorenz Padberg <lorenz.padberg@iterativ.ch>
Date:   Thu Sep 15 11:39:01 2022 +0200

    Revert "Upgrade to Wagtail 4.0"

    This reverts commit e6f43f6b11e91a923badbaec33ab460a3cfac60e.

commit d5b28e362f604d17fed32fabe8295865b82350de
Author: Lorenz Padberg <lorenz.padberg@iterativ.ch>
Date:   Thu Sep 15 11:38:14 2022 +0200

    Add factories for category content

commit e6ebabc1c6b01ccbc14413bbe40e71a348dfa565
Author: Lorenz Padberg <lorenz.padberg@iterativ.ch>
Date:   Tue Sep 13 16:10:58 2022 +0200

    Simplify Mediathek models

commit b4dd179b891960babb8c26a70d3cecfcabb72264
Author: Lorenz Padberg <lorenz.padberg@iterativ.ch>
Date:   Mon Sep 12 15:53:00 2022 +0200

    Add Document and Link to Mediathek

commit 707ab8d9abc622f3ef5935472ddc7e7c74a352e6
Author: Lorenz Padberg <lorenz.padberg@iterativ.ch>
Date:   Mon Sep 12 14:16:49 2022 +0200

    Add Media Library Models, including factory and default data

commit e6f43f6b11e91a923badbaec33ab460a3cfac60e
Author: Lorenz Padberg <lorenz.padberg@iterativ.ch>
Date:   Mon Sep 12 11:09:46 2022 +0200

    Upgrade to Wagtail 4.0
This commit is contained in:
Daniel Egger 2022-09-19 13:53:30 +02:00
parent 722b9f7937
commit a75a29f57c
11 changed files with 443 additions and 98 deletions

View File

@ -16,7 +16,7 @@ class LearningPath(Page):
# PageChooserPanel('related_page', 'demo.PublisherPage'), # PageChooserPanel('related_page', 'demo.PublisherPage'),
content_panels = Page.content_panels content_panels = Page.content_panels
subpage_types = ['learnpath.Circle', 'learnpath.Topic'] subpage_types = ['learnpath.Circle', 'learnpath.Topic', 'media_library.MediaLibrary']
class Meta: class Meta:
verbose_name = "Learning Path" verbose_name = "Learning Path"

View File

@ -0,0 +1,72 @@
from django.db import models
from wagtail import blocks
from wagtail.admin.panels import FieldPanel
from wagtail.snippets.models import register_snippet
from wagtail.documents.blocks import DocumentChooserBlock
from django.utils.translation import gettext_lazy as _
class VisualisationType(models.TextChoices):
LEARNING_MEDIA = 'LearningMedia', _('Lernmedien')
LINK = 'Link', _('Links')
ANKER = 'Anker', _('Verankerung')
CROSSREFERENCE = 'CrossReference', _('Querverweise')
@register_snippet
class MediaLibraryContent(models.Model):
title = models.TextField()
description = models.TextField()
link_display_text = models.CharField(max_length=255)
# TODO: Revisions only work with wagtail 4.0, can not migrate since wagtail localize is not ready yet.
# _revisions = GenericRelation("wagtailcore.Revision", related_query_name="media_library_content")
panels = [
FieldPanel('title'),
FieldPanel('description'),
FieldPanel('link_display_text'),
]
@property
def revisions(self):
return self._revisions
class AnkerBlock(blocks.PageChooserBlock):
"""
Verankerung im Lernpfad. Link to a Learning Content.
"""
page_type = 'learnpath.LearningUnit'
class LinkBlock(blocks.StructBlock):
title = blocks.TextBlock(blank=False, null=False)
description = blocks.TextBlock(default='')
link_display_text = blocks.CharBlock(max_length=255, default='Link öffnen')
url = blocks.URLBlock()
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')
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())
])
class Meta:
icon = 'link'

View File

@ -0,0 +1,28 @@
import json
from vbv_lernwelt.learnpath.models import LearningPath
from vbv_lernwelt.media_library.tests.media_library_factories import MediaLibraryFactory, TopCategoryFactory, \
CategoryFactory, ContentCollectionFactory, collection_body_dict
from vbv_lernwelt.media_library.models import Category
def create_default_media_library():
lp = LearningPath.objects.all().first()
m = MediaLibraryFactory(title='Mediathek', parent=lp)
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)

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
#
# Iterativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2015 Iterativ GmbH. All rights reserved.
#
# Created on 2022-09-14
# @author: lorenz.padberg@iterativ.ch
[{"id": "a2a7ef07-64d9-444e-8069-4894a1e857ee",
"type": "content_collection",
"value": {"title": "Lernmedien",
"contents": [{
"id": "5b24aa0b-17d7-4b04-8698-f86d2116d6df",
"type": "Documents",
"value": 2}, {
"id": "e2d43794-037f-4a19-8a71-c7e9d96d8dac",
"type": "Documents",
"value": 1}],
"collection_type": [
"LearningMedia"]}
},
{"id": "23d13543-2f37-44b8-b3e2-0ef36f7c5a13",
"type": "content_collection",
"value": {"title": "Links", "contents": [
{"id": "57e35e12-ceb3-4873-9629-a6c5a3c2f6da",
"type": "Links",
"value": {"url": "http://www.admin.ch",
"title": "Wichtige Webseite",
"description": "interessantes zu versicherungen",
"link_display_text": "Link öffnen"}}],
"collection_type": [
"LearningMedia"]}}]

View File

@ -1,10 +1,11 @@
import djclick as click import djclick as click
from vbv_lernwelt.media_library.create_default_documents import create_default_collections, create_default_documents 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
@click.command() @click.command()
def command(): def command():
create_default_media_library()
create_default_collections() create_default_collections()
create_default_documents() create_default_documents()

View File

@ -1,42 +0,0 @@
# Generated by Django 3.2.13 on 2022-08-18 12:14
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0069_log_entry_jsonfield'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
('media_library', '0001_initial'),
]
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')),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='TopCategory',
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.RenameModel(
old_name='CustomDocument',
new_name='LibraryDocument',
),
]

View File

@ -0,0 +1,68 @@
# Generated by Django 3.2.13 on 2022-09-14 13:02
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import vbv_lernwelt.media_library.content_blocks
import wagtail.blocks
import wagtail.documents.blocks
import wagtail.fields
class Migration(migrations.Migration):
dependencies = [
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('wagtailcore', '0069_log_entry_jsonfield'),
('media_library', '0001_initial'),
]
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=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.TextField()),
('description', models.TextField()),
('link_display_text', models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name='TopCategory',
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.RenameModel(
old_name='CustomDocument',
new_name='LibraryDocument',
),
]

View File

@ -1,8 +1,55 @@
from wagtail import blocks, fields
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
from django.db import models from django.db import models
# Create your models here. # Create your models here.
from wagtail.models import Page from wagtail.models import Page
from wagtail.documents.models import AbstractDocument, Document from wagtail.documents.models import AbstractDocument, Document
from wagtail.snippets.blocks import SnippetChooserBlock
from vbv_lernwelt.media_library.content_blocks import ContentCollection
class MediaLibrary(Page):
parent_page_types = ['learnpath.LearningPath']
subpage_types = ['media_library.TopCategory']
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"),
]
# Todo: use wagtail collections for this... Only applicable for documents, since links etc. dont have collections
class Category(Page):
"""
Handlungsfeld. zB. Fahrzeug
"""
parent_page_types = ['media_library.TopCategory']
introduction_text = models.TextField(default='')
description = fields.RichTextField(default='')
body = fields.StreamField([('content_collection', ContentCollection())
], use_json_field=True, null=True)
content_panels = [
FieldPanel('title', classname="full title"),
FieldPanel('introduction_text', classname="introduction text"),
FieldPanel('description', classname="introduction text"),
StreamFieldPanel('body')
]
class LibraryDocument(AbstractDocument): class LibraryDocument(AbstractDocument):
@ -14,58 +61,6 @@ class LibraryDocument(AbstractDocument):
link_display_text = models.CharField(max_length=1024, default='') link_display_text = models.CharField(max_length=1024, default='')
thumbnail = models.URLField() thumbnail = models.URLField()
admin_form_fields = Document.admin_form_fields + ( admin_form_fields = Document.admin_form_fields + (
'display_text', 'description', 'link_display_text', 'thumbnail' 'display_text', 'description', 'link_display_text', 'thumbnail'
) )
class TopCategory(Page):
"""
Handlungsfelder
"""
parent_page_types = ['learnpath.LearningPath']
subpage_types = ['media_library.Category']
# Todo: use wagtail collections for this...
class Category(Page):
"""
Handlungsfeld
"""
parent_page_types = ['media_library.TopCategory']
#
# description
# thumbnail_image
# description_image
# additional_content # Rich text field
# documents = []
#
#
# class LibraryDocument(CustomDocument):
# """
# Extension from the standart Wagtail document.
# """
# pass
#
#
# class LibraryLink():
# """
# Custom Link Block
#
# """
# pass
#
#
# class LearningPathReference():
# icon
# pass
#
#
# class CrossReference():
# pass

View File

@ -1,9 +1,11 @@
import json
import wagtail_factories import wagtail_factories
import factory
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningContent, LearningUnit, \ from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningContent, LearningUnit, \
LearningUnitQuestion LearningUnitQuestion
from vbv_lernwelt.media_library.models import LibraryDocument from vbv_lernwelt.media_library.models import LibraryDocument, MediaLibrary, TopCategory, Category
from vbv_lernwelt.media_library.content_blocks import ContentCollection, AnkerBlock, LinkBlock, CrossReferenceBlock
class LibraryDocumentFactory(wagtail_factories.DocumentFactory): class LibraryDocumentFactory(wagtail_factories.DocumentFactory):
@ -13,3 +15,110 @@ class LibraryDocumentFactory(wagtail_factories.DocumentFactory):
class Meta: class Meta:
model = LibraryDocument model = LibraryDocument
class MediaLibraryFactory(wagtail_factories.PageFactory):
title = 'Mediathek'
class Meta:
model = MediaLibrary
class TopCategoryFactory(wagtail_factories.PageFactory):
title = 'Handlungsfelder'
class Meta:
model = TopCategory
class AnkerBlockFactory(wagtail_factories.StructBlockFactory):
class Meta:
model = AnkerBlock
class LinkBlockFactory(wagtail_factories.StructBlockFactory):
title = 'Interesting link'
description = 'This link is really interesting...'
url = 'www.example.com'
class Meta:
model = LinkBlock
class CrossReferenceBlockFactory(wagtail_factories.StructBlockFactory):
class Meta:
model = CrossReferenceBlock
class ContentCollectionFactory(wagtail_factories.StructBlockFactory):
title = 'Links'
contents = wagtail_factories.StreamFieldFactory({
'Links': LinkBlockFactory,
'Documents': LibraryDocumentFactory
})
class Meta:
model = ContentCollection
class CategoryFactory(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
def generate_default_category():
category = CategoryFactory()
category.body = json.dumps(collection_body_dict())
category.save()
return category
def generate_default_content_string(
block_type='Links',
content_idx=0,
content_property='url',
stream_field_name='contents'):
return f'{stream_field_name}__{content_idx}__{block_type}__{content_property}'
def generate_default_content2(**contents_dict):
# TODO: hierarchical test, has to be refactored.
stream_field_name = 'contents'
content_idx = 0
block_type = 'Links'
content_property = 'url'
value = 'iterativ.ch'
contents_dict[
f'body__content_collection__0__{stream_field_name}__{content_idx}__{block_type}__{content_property}'] = value
return contents_dict
def link_dict(link_block=LinkBlockFactory()):
d = {
"type": "Links",
"collection_type": ["LearningMedia"],
"value": block_to_dict(link_block)}
return d
def document_dict(document=LibraryDocumentFactory()):
d = {
"type": "Documents",
"id": document.id
}
return d
def block_to_dict(block):
return dict(block.items())
def collection_body_dict():
d = [{"type": "content_collection",
"value": {"title": "Links", "contents": [link_dict()], }},
{"type": "content_collection",
"value": {"title": "Lernmedien", "contents": [document_dict()], }}]

View File

@ -0,0 +1,32 @@
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
class TestCreateDefaultDocuments(TestCase):
def setUp(self) -> None:
create_default_users()
create_locales_for_wagtail()
LearningPathFactory()
create_default_media_library()
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)
def test_create_category_fahrzeug_contains_content(self):
fahrzeug = Category.objects.get(title='Fahrzeug')

View File

@ -0,0 +1,49 @@
import json
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.models import LibraryDocument, Category
from vbv_lernwelt.media_library.tests.media_library_factories import ContentCollectionFactory, CategoryFactory, \
LinkBlockFactory, generate_default_category, generate_default_content2, collection_body_dict
class TestMediaLibraryFactories(TestCase):
def setUp(self) -> None:
create_default_users()
create_locales_for_wagtail()
def test_content_collection_factory(self):
content_collection = ContentCollectionFactory()
self.assertEqual(content_collection.get('title'), 'Links')
self.assertEqual(content_collection.get('collection_type'), 'LearningMedia')
def test_link_block_factory(self):
link = LinkBlockFactory(title='MyLink')
self.assertEqual(link.get('description'), 'This link is really interesting...')
self.assertEqual(link.get('url'), 'www.example.com')
self.assertEqual(link.get('link_display_text'), 'Link öffnen')
self.assertEqual(link.get('title'), 'MyLink')
def test_category_contains_content_collection(self):
default_content = generate_default_content2()
default_content['body__content_collection__0__title'] = 'Spidf'
category = CategoryFactory(**default_content)
print(category.body.raw_data)
self.assertNotEqual(category.body.raw_data, [])
def collection_via_dict_generation(self):
category = CategoryFactory()
category.body = json.dumps(collection_body_dict())
category.save()
category_id = category.id
new_category = Category.objects.get(id=category_id)
self.assertNotEqual(new_category.body, [])
self.assertNotEqual(new_category.body, [])