diff --git a/server/vbv_lernwelt/learnpath/migrations/0003_auto_20220512_1456.py b/server/vbv_lernwelt/learnpath/migrations/0003_auto_20220512_1456.py new file mode 100644 index 00000000..6e3dd602 --- /dev/null +++ b/server/vbv_lernwelt/learnpath/migrations/0003_auto_20220512_1456.py @@ -0,0 +1,36 @@ +# Generated by Django 3.2.12 on 2022-05-12 12:56 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('learnpath', '0002_fullfillmentcriteria_sort_order'), + ] + + operations = [ + migrations.RemoveField( + model_name='learningunit', + name='learning_sequence', + ), + migrations.CreateModel( + name='LearningPackage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), + ('title', models.CharField(default='', max_length=256)), + ('learning_sequence', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_packages', to='learnpath.learningsequence')), + ], + options={ + 'ordering': ['sort_order'], + 'abstract': False, + }, + ), + migrations.AddField( + model_name='learningunit', + name='learning_package', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_units', to='learnpath.learningpackage'), + ), + ] diff --git a/server/vbv_lernwelt/learnpath/migrations/0004_alter_learningpackage_learning_sequence.py b/server/vbv_lernwelt/learnpath/migrations/0004_alter_learningpackage_learning_sequence.py new file mode 100644 index 00000000..fd4b51c7 --- /dev/null +++ b/server/vbv_lernwelt/learnpath/migrations/0004_alter_learningpackage_learning_sequence.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.12 on 2022-05-12 12:56 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('learnpath', '0003_auto_20220512_1456'), + ] + + operations = [ + migrations.AlterField( + model_name='learningpackage', + name='learning_sequence', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='learning_packages', to='learnpath.learningsequence'), + ), + ] diff --git a/server/vbv_lernwelt/learnpath/migrations/0005_alter_learningunit_learning_package.py b/server/vbv_lernwelt/learnpath/migrations/0005_alter_learningunit_learning_package.py new file mode 100644 index 00000000..6a1128a7 --- /dev/null +++ b/server/vbv_lernwelt/learnpath/migrations/0005_alter_learningunit_learning_package.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.12 on 2022-05-12 12:56 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('learnpath', '0004_alter_learningpackage_learning_sequence'), + ] + + operations = [ + migrations.AlterField( + model_name='learningunit', + name='learning_package', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='learning_units', to='learnpath.learningpackage'), + ), + ] diff --git a/server/vbv_lernwelt/learnpath/models.py b/server/vbv_lernwelt/learnpath/models.py index 34b8bd28..179f72c2 100644 --- a/server/vbv_lernwelt/learnpath/models.py +++ b/server/vbv_lernwelt/learnpath/models.py @@ -1,19 +1,22 @@ # Create your models here. -from django.db import models -from modelcluster.fields import ParentalKey -from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, InlinePanel +from django.utils.text import slugify from wagtail.core.blocks import StreamBlock from wagtail.core.fields import StreamField from wagtail.core.models import Page, Orderable -from django.utils.text import slugify - - -from vbv_lernwelt.learnpath.models_learning_unit_content import WebBasedTrainingBlock, VideoBlock from vbv_lernwelt.learnpath.models_competences import * +from vbv_lernwelt.learnpath.models_learning_unit_content import WebBasedTrainingBlock, VideoBlock +from grapple.helpers import register_query_field +import graphene + +from grapple.models import ( + GraphQLString, GraphQLPage, + GraphQLStreamfield, GraphQLBoolean, GraphQLInt, GraphQLForeignKey, GraphQLField +) +@register_query_field("learning_path") class LearningPath(Page): # PageChooserPanel('related_page', 'demo.PublisherPage'), @@ -23,6 +26,10 @@ class LearningPath(Page): subpage_types = ['learnpath.Circle'] + graphql_fields = [ + GraphQLString("title", required=True), + ] + class Meta: verbose_name = "Learning Path" @@ -45,6 +52,11 @@ class Topic(Orderable): FieldPanel('is_visible'), ] + graphql_fields = [ + GraphQLString("title"), + GraphQLBoolean("is_visible"), + ] + # content_panels = Page.content_panels + [ # FieldPanel('is_visible', classname="full"), # PageChooserPanel('learning_path', 'learnpath.LearningPath'), @@ -56,7 +68,6 @@ class Topic(Orderable): self.slug = find_available_slug(Topic, slugify(self.title, allow_unicode=True)) super(Topic, self).full_clean(*args, **kwargs) - class Meta: verbose_name = "Topic" @@ -84,6 +95,13 @@ class Circle(Page, Orderable): FieldPanel('goals'), InlinePanel('learning_sequences', label="Learning Sequences"), ] + # + graphql_fields = [ + GraphQLString("title", required=True), + GraphQLString("description"), + GraphQLString("goals"), + ] + def full_clean(self, *args, **kwargs): self.slug = find_available_slug(Circle, slugify(self.title, allow_unicode=True)) @@ -92,8 +110,6 @@ class Circle(Page, Orderable): class Meta: verbose_name = "Circle" - - def __str__(self): return f"{self.title}" @@ -121,9 +137,16 @@ class LearningSequence(Orderable): on_delete=models.CASCADE, related_name='learning_sequences', ) - icon = "" - panels = [FieldPanel('title'), FieldPanel('category')] + panels = [FieldPanel('title'), FieldPanel('category'), FieldPanel('circle')] + + + + graphql_fields = [ + GraphQLString("title", required=True), + GraphQLBoolean("category"), + ] + class Meta: verbose_name = "Learning Sequence" @@ -131,15 +154,46 @@ class LearningSequence(Orderable): def __str__(self): return f"{self.title}" + def full_clean(self, *args, **kwargs): + self.slug = find_available_slug(LearningSequence, slugify(self.title, allow_unicode=True)) + super(LearningSequence, self).full_clean(*args, **kwargs) + + + +class LearningPackage(Orderable): + title = models.CharField(max_length=256, default='') -class LearningUnit(Page, Orderable): - # TODO: Review model architecture, is the stream field the right thing here? - parent_page_types = ['learnpath.Circle'] learning_sequence = models.ForeignKey( 'learnpath.LearningSequence', null=True, blank=True, - on_delete=models.CASCADE, + on_delete=models.SET_NULL, + related_name='learning_packages', + ) + panels = [FieldPanel('title')] + + graphql_fields = [ + GraphQLString("title", required=False), + ] + + + def full_clean(self, *args, **kwargs): + self.slug = find_available_slug(LearningPackage, slugify(self.title, allow_unicode=True)) + super(LearningPackage, self).full_clean(*args, **kwargs) + + +class LearningUnit(Page, Orderable): + """ + This is a group of contents, with the übung and test it is one unit. ... more of a structural charactacter. + + """ + # TODO: Review model architecture, is the stream field the right thing here? + parent_page_types = ['learnpath.Circle'] + learning_package = models.ForeignKey( + 'learnpath.LearningPackage', + null=True, + blank=True, + on_delete=models.SET_NULL, related_name='learning_units', ) @@ -153,10 +207,15 @@ class LearningUnit(Page, Orderable): content_panels = [ FieldPanel('title', classname="full title"), - FieldPanel('learning_sequence'), + FieldPanel('learning_package'), StreamFieldPanel('contents'), ] + graphql_fields = [ + GraphQLString("title", required=True), + GraphQLStreamfield('contents') + ] + subpage_types = [] class Meta: @@ -170,6 +229,7 @@ class LearningUnit(Page, Orderable): return f"{self.title}" + def find_available_slug(model, requested_slug, ignore_page_id=None): """ Finds an available slug within the specified parent. @@ -197,7 +257,6 @@ def find_available_slug(model, requested_slug, ignore_page_id=None): slug = requested_slug number = 1 - while slug in existing_slugs: slug = requested_slug + "-" + str(number) number += 1 diff --git a/server/vbv_lernwelt/learnpath/tests/create_default_learning_path.py b/server/vbv_lernwelt/learnpath/tests/create_default_learning_path.py index 82df2b20..f9e84e86 100644 --- a/server/vbv_lernwelt/learnpath/tests/create_default_learning_path.py +++ b/server/vbv_lernwelt/learnpath/tests/create_default_learning_path.py @@ -4,10 +4,7 @@ from wagtail.core.models import Site from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningUnit from vbv_lernwelt.learnpath.tests.create_default_competences import create_default_competences from vbv_lernwelt.learnpath.tests.learningpath_factories import LearningPathFactory, TopicFactory, CircleFactory, \ - LearningSequenceFactory, LearningUnitFactory, VideoBlockFactory, WebBasedTrainingBlockFactory - - - + LearningSequenceFactory, LearningUnitFactory, VideoBlockFactory, WebBasedTrainingBlockFactory, LearningPackageFactory def create_default_learning_path(): @@ -27,10 +24,17 @@ def create_default_learning_path(): damit erfolgreich mit deinem Lernpfad starten kannst.""") ls_1 = LearningSequenceFactory(title='Einleitung', circle=circle_1) - lu_1 = LearningUnitFactory(title="Herzlich Willkommmen", parent=circle_1, learning_sequence=ls_1) + + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=ls_1) + + lu_1 = LearningUnitFactory(title="Herzlich Willkommmen", parent=circle_1, learning_package=lpck_1) + lu_1 = LearningUnitFactory(title="Herzlich Willkommmen 1", parent=circle_1, learning_package=lpck_1) + lu_1 = LearningUnitFactory(title="Herzlich Willkommmen 2", parent=circle_1, learning_package=lpck_1) ls_2 = LearningSequenceFactory(title='Grundlagen', circle=circle_1) - lu_1 = LearningUnitFactory(title="Aber jetzt, Butter bei die Fische", parent=circle_1, learning_sequence=ls_2) + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=ls_2) + + lu_1 = LearningUnitFactory(title="Aber jetzt, Butter bei die Fische", parent=circle_1, learning_package=lpck_1) tp = TopicFactory(title="Gewinnen von Kunden", learning_path=lp) @@ -67,10 +71,10 @@ von Neukunden zu benützen zu visualisieren""") sequence_1 = LearningSequenceFactory(title="Starten", circle=circle_4) - learning_unit = LearningUnitFactory(title='Einleitung Circle "Anlayse"', parent=circle_4, learning_sequence=sequence_1) - learning_unit.learning_sequence = sequence_1 + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_1) - learning_unit = LearningUnitFactory.create(title='** Einstieg Video"', parent=circle_4, learning_sequence=sequence_1) + learning_unit = LearningUnitFactory(title='Einleitung Circle "Anlayse"', parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title='** Einstieg Video"', parent=circle_4, learning_package=lpck_1) video_url = "https://www.vbv.ch/fileadmin/vbv/Videos/Statements_Externe/Janos_M/Testimonial_Janos_Mischler_PositiveEffekte.mp4" video_title = "Ausbildung ist pflicht" video_description = "Erfahren Sie, was für Janos Mischler die positiven Aspekte von ständiger Weiterbildung sind – aus fachlicher und aus persönlicher Sicht." @@ -78,39 +82,56 @@ von Neukunden zu benützen learning_unit.contents.append(('video', video_block)) learning_unit.save() - learning_unit = LearningUnitFactory.create(title='** Web Based Training"', parent=circle_4, learning_sequence=sequence_1) + learning_unit = LearningUnitFactory.create(title='** Web Based Training"', parent=circle_4, learning_package=lpck_1) wbt_url = "web_based_trainings/rise_cmi5_test_export/scormcontent/index.html" wbt_block = WebBasedTrainingBlockFactory(type="web_based_training", url=wbt_url) learning_unit.contents.append(('web_based_training', wbt_block)) learning_unit.save() - learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4, learning_sequence=sequence_1) + learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4, learning_package=lpck_1) sequence_2 = LearningSequenceFactory.create(title="Beobachten", circle=circle_4) - learning_unit = LearningUnitFactory.create(title="Mein Motorfahrzeug kaufen", parent=circle_4, learning_sequence=sequence_2) - learning_unit = LearningUnitFactory.create(title="Sich selbständig machen", parent=circle_4, learning_sequence=sequence_2) + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_2) + + learning_unit = LearningUnitFactory.create(title="Mein Motorfahrzeug kaufen", parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title="Sich selbständig machen", parent=circle_4, learning_package=lpck_1) sequence_3 = LearningSequenceFactory.create(title="Anwenden", circle=circle_4) - learning_unit = LearningUnitFactory.create(title="Nora kauft sich ein neues Auto", parent=circle_4, learning_sequence=sequence_3) - learning_unit = LearningUnitFactory.create(title="Manuel träumt von einem neuen Tesla", parent=circle_4, learning_sequence=sequence_3) - learning_unit = LearningUnitFactory.create(title="Deine Erkenntnisse und Learnings", parent=circle_4, learning_sequence=sequence_3) + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_3) + + learning_unit = LearningUnitFactory.create(title="Nora kauft sich ein neues Auto", parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title="Manuel träumt von einem neuen Tesla", parent=circle_4, learning_package=lpck_1) + + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_3) + + learning_unit = LearningUnitFactory.create(title="Deine Erkenntnisse und Learnings", parent=circle_4, learning_package=lpck_1) sequence_4 = LearningSequenceFactory.create(title="Üben", circle=circle_4) - learning_unit = LearningUnitFactory.create(title="Ermittlung des Kundenbedarfs", parent=circle_4, learning_sequence=sequence_4) - learning_unit = LearningUnitFactory.create(title="Aktives Zuhören", parent=circle_4, learning_sequence=sequence_4) - learning_unit = LearningUnitFactory.create(title="In Bildern Sprechen", parent=circle_4, learning_sequence=sequence_4) - learning_unit = LearningUnitFactory.create(title="Priorisieren des Bedarfs", parent=circle_4, learning_sequence=sequence_4) - learning_unit = LearningUnitFactory.create(title="Zusammenfassung des Bedarfs", parent=circle_4, learning_sequence=sequence_4) + + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_4) + learning_unit = LearningUnitFactory.create(title="Ermittlung des Kundenbedarfs", parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title="Aktives Zuhören", parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title="In Bildern Sprechen", parent=circle_4, learning_package=lpck_1) + + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_4) + learning_unit = LearningUnitFactory.create(title="Priorisieren des Bedarfs", parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title="Zusammenfassung des Bedarfs", parent=circle_4, learning_package=lpck_1) sequence_5 = LearningSequenceFactory.create(title="Testen", circle=circle_4) - learning_unit = LearningUnitFactory.create(title="Bedarfsfragen", parent=circle_4, learning_sequence=sequence_5) - learning_unit = LearningUnitFactory.create(title="Andwendung der Fragetechniken", parent=circle_4, learning_sequence=sequence_5) + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_5) + + learning_unit = LearningUnitFactory.create(title="Bedarfsfragen", parent=circle_4, learning_package=lpck_1) + learning_unit = LearningUnitFactory.create(title="Andwendung der Fragetechniken", parent=circle_4, learning_package=lpck_1) sequence_5 = LearningSequenceFactory.create(title="Vernetzen", circle=circle_4) - learning_unit = LearningUnitFactory.create(title="Online Training", parent=circle_4, learning_sequence=sequence_5) + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_5) + + learning_unit = LearningUnitFactory.create(title="Online Training", parent=circle_4, learning_package=lpck_1) sequence_6 = LearningSequenceFactory.create(title="Beenden", circle=circle_4) - learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4, learning_sequence=sequence_6) + lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_6) + + learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4, learning_package=lpck_1) circle_5 = CircleFactory.create(title="Lösung", parent=lp, diff --git a/server/vbv_lernwelt/learnpath/tests/grapple_test.http b/server/vbv_lernwelt/learnpath/tests/grapple_test.http index e69de29b..883b9d03 100644 --- a/server/vbv_lernwelt/learnpath/tests/grapple_test.http +++ b/server/vbv_lernwelt/learnpath/tests/grapple_test.http @@ -0,0 +1,20 @@ +GET http://localhost:8000/graphql/ +Accept: application/json + +### +{ + page(id: 8) { + + children { + __typename + id + title + children { + __typename + + id + title + } + } + } +} diff --git a/server/vbv_lernwelt/learnpath/tests/grapple_test.txt b/server/vbv_lernwelt/learnpath/tests/grapple_test.txt index e69de29b..51917e32 100644 --- a/server/vbv_lernwelt/learnpath/tests/grapple_test.txt +++ b/server/vbv_lernwelt/learnpath/tests/grapple_test.txt @@ -0,0 +1,17 @@ +{ + page(id: 8) { + + children { + __typename + id + title + children { + __typename + + id + title + } + } + } +} + diff --git a/server/vbv_lernwelt/learnpath/tests/learningpath_factories.py b/server/vbv_lernwelt/learnpath/tests/learningpath_factories.py index 3566a7fe..3e9ff9c8 100644 --- a/server/vbv_lernwelt/learnpath/tests/learningpath_factories.py +++ b/server/vbv_lernwelt/learnpath/tests/learningpath_factories.py @@ -1,6 +1,6 @@ import wagtail_factories import factory -from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningUnit +from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningUnit, LearningPackage from vbv_lernwelt.learnpath.models_learning_unit_content import VideoBlock, WebBasedTrainingBlock @@ -32,6 +32,12 @@ class LearningSequenceFactory(factory.django.DjangoModelFactory): class Meta: model = LearningSequence +class LearningPackageFactory(factory.django.DjangoModelFactory): + title = "Whatever" + + class Meta: + model = LearningPackage + class LearningUnitFactory(wagtail_factories.PageFactory): title = "Herzlich Willkommen"