353 lines
9.9 KiB
Python
353 lines
9.9 KiB
Python
from django.db import models
|
|
from django.utils.text import slugify
|
|
from wagtail import blocks
|
|
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
|
|
from wagtail.blocks import StreamBlock
|
|
from wagtail.fields import StreamField
|
|
from wagtail.images.blocks import ImageChooserBlock
|
|
from wagtail.models import Page
|
|
|
|
from vbv_lernwelt.core.model_utils import find_available_slug
|
|
from vbv_lernwelt.course.models import CoursePage
|
|
from vbv_lernwelt.learnpath.models_learning_unit_content import (
|
|
AssignmentBlock,
|
|
BookBlock,
|
|
DocumentBlock,
|
|
ExerciseBlock,
|
|
MediaLibraryBlock,
|
|
OnlineTrainingBlock,
|
|
PlaceholderBlock,
|
|
ResourceBlock,
|
|
TestBlock,
|
|
VideoBlock,
|
|
)
|
|
from vbv_lernwelt.learnpath.serializer_helpers import get_it_serializer_class
|
|
|
|
|
|
class LearningPath(Page):
|
|
content_panels = Page.content_panels
|
|
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(f"{self.get_parent().slug}-lp", allow_unicode=True)
|
|
)
|
|
super(LearningPath, self).full_clean(*args, **kwargs)
|
|
|
|
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,
|
|
[
|
|
"children",
|
|
"course",
|
|
],
|
|
)
|
|
|
|
|
|
class Topic(Page):
|
|
# title = models.TextField(default='')
|
|
is_visible = models.BooleanField(default=True)
|
|
|
|
parent_page_types = ["learnpath.LearningPath"]
|
|
|
|
panels = [
|
|
FieldPanel("title"),
|
|
FieldPanel("is_visible"),
|
|
]
|
|
|
|
# content_panels = Page.content_panels + [
|
|
# FieldPanel('is_visible', classname="full"),
|
|
# PageChooserPanel('learning_path', 'learnpath.LearningPath'),
|
|
# ]
|
|
|
|
# parent_page_types = ['learnpath.LearningPath']
|
|
# subpage_types = ['learnpath.Circle']
|
|
|
|
def full_clean(self, *args, **kwargs):
|
|
self.slug = find_slug_with_parent_prefix(self, "topic")
|
|
super(Topic, self).full_clean(*args, **kwargs)
|
|
|
|
@classmethod
|
|
def get_serializer_class(cls):
|
|
return get_it_serializer_class(
|
|
cls,
|
|
field_names=[
|
|
"is_visible",
|
|
],
|
|
)
|
|
|
|
def get_admin_display_title(self):
|
|
return f"Thema: {self.draft_title}"
|
|
|
|
class Meta:
|
|
verbose_name = "Topic"
|
|
|
|
def __str__(self):
|
|
return f"{self.title}"
|
|
|
|
|
|
class PersonBlock(blocks.StructBlock):
|
|
first_name = blocks.CharBlock()
|
|
last_name = blocks.CharBlock()
|
|
email = blocks.EmailBlock()
|
|
photo = ImageChooserBlock(required=False)
|
|
biography = blocks.RichTextBlock(required=False)
|
|
|
|
class Meta:
|
|
icon = "user"
|
|
|
|
|
|
class Circle(Page):
|
|
description = models.TextField(default="", blank=True)
|
|
goals = StreamField(
|
|
[
|
|
("goal", blocks.TextBlock()),
|
|
],
|
|
use_json_field=True,
|
|
)
|
|
job_situations = StreamField(
|
|
[
|
|
("job_situation", blocks.CharBlock()),
|
|
],
|
|
use_json_field=True,
|
|
)
|
|
experts = StreamField(
|
|
[
|
|
("person", PersonBlock()),
|
|
],
|
|
use_json_field=True,
|
|
)
|
|
|
|
parent_page_types = ["learnpath.LearningPath"]
|
|
subpage_types = [
|
|
"learnpath.LearningSequence",
|
|
"learnpath.LearningUnit",
|
|
"learnpath.LearningContent",
|
|
]
|
|
|
|
content_panels = Page.content_panels + [
|
|
FieldPanel("description"),
|
|
FieldPanel("goals"),
|
|
FieldPanel("job_situations"),
|
|
FieldPanel("experts"),
|
|
]
|
|
|
|
@classmethod
|
|
def get_serializer_class(cls):
|
|
return get_it_serializer_class(
|
|
cls,
|
|
field_names=[
|
|
"children",
|
|
"description",
|
|
"job_situations",
|
|
"goals",
|
|
"experts",
|
|
],
|
|
)
|
|
|
|
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)
|
|
|
|
class Meta:
|
|
verbose_name = "Circle"
|
|
|
|
def __str__(self):
|
|
return f"{self.title}"
|
|
|
|
|
|
class LearningSequence(Page):
|
|
parent_page_types = ["learnpath.Circle"]
|
|
subpage_types = []
|
|
|
|
icon = models.CharField(max_length=255, default="it-icon-ls-start")
|
|
|
|
content_panels = Page.content_panels + [
|
|
FieldPanel("icon"),
|
|
]
|
|
|
|
class Meta:
|
|
verbose_name = "Learning Sequence"
|
|
|
|
def __str__(self):
|
|
return f"{self.title}"
|
|
|
|
@classmethod
|
|
def get_serializer_class(cls):
|
|
return get_it_serializer_class(cls, field_names=["icon"])
|
|
|
|
def get_admin_display_title(self):
|
|
return f"{self.icon} {self.draft_title}"
|
|
|
|
def get_admin_display_title_html(self):
|
|
return f"""
|
|
<span style="display: inline-flex; align-items: center; font-size: 1.25rem; font-weight: 700;">
|
|
<{self.icon} style="height: 32px; width: 32px;"></{self.icon}>
|
|
<span style="margin-left: 8px;">{self.draft_title}</span>
|
|
</span>"""
|
|
|
|
def get_admin_display_title(self):
|
|
return f"LS: {self.draft_title}"
|
|
|
|
def full_clean(self, *args, **kwargs):
|
|
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"]
|
|
subpage_types = []
|
|
course_category = models.ForeignKey(
|
|
"course.CourseCategory", on_delete=models.SET_NULL, null=True, blank=True
|
|
)
|
|
|
|
content_panels = Page.content_panels + [
|
|
FieldPanel("course_category"),
|
|
]
|
|
|
|
class Meta:
|
|
verbose_name = "Learning Unit"
|
|
|
|
def __str__(self):
|
|
return f"{self.title}"
|
|
|
|
def full_clean(self, *args, **kwargs):
|
|
course = None
|
|
course_parent_page = self.get_ancestors().exact_type(CoursePage).last()
|
|
if course_parent_page:
|
|
course = course_parent_page.specific.course
|
|
|
|
if self.course_category is None and course:
|
|
self.course_category = course.coursecategory_set.filter(
|
|
general=True
|
|
).first()
|
|
|
|
if self.course_category.general:
|
|
self.slug = find_slug_with_parent_prefix(self, "lu")
|
|
else:
|
|
self.slug = find_slug_with_parent_prefix(
|
|
self, "lu", self.course_category.title
|
|
)
|
|
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}"
|
|
|
|
def get_admin_display_title(self):
|
|
return f"LE: {self.draft_title}"
|
|
|
|
@classmethod
|
|
def get_serializer_class(cls):
|
|
from vbv_lernwelt.learnpath.serializers import LearningUnitSerializer
|
|
|
|
return LearningUnitSerializer
|
|
|
|
def get_admin_display_title_html(self):
|
|
return f'<span style="font-weight: 700; font-size: 20px;">{self.draft_title}</span>'
|
|
|
|
|
|
class LearningContent(Page):
|
|
parent_page_types = ["learnpath.Circle"]
|
|
subpage_types = []
|
|
|
|
minutes = models.PositiveIntegerField(default=15)
|
|
|
|
content_blocks = [
|
|
("video", VideoBlock()),
|
|
("resource", ResourceBlock()),
|
|
("exercise", ExerciseBlock()),
|
|
("online_training", OnlineTrainingBlock()),
|
|
("media_library", MediaLibraryBlock()),
|
|
("document", DocumentBlock()),
|
|
("test", TestBlock()),
|
|
("book", BookBlock()),
|
|
("assignment", AssignmentBlock()),
|
|
("placeholder", PlaceholderBlock()),
|
|
]
|
|
|
|
contents = StreamField(
|
|
StreamBlock(content_blocks), blank=False, min_num=1, max_num=1
|
|
)
|
|
|
|
content_panels = [
|
|
FieldPanel("title", classname="full title"),
|
|
FieldPanel("minutes"),
|
|
StreamFieldPanel("contents"),
|
|
]
|
|
|
|
def get_admin_display_title(self):
|
|
display_title = ""
|
|
|
|
if len(self.contents) > 0:
|
|
display_title += f"{self.contents[0].block_type.capitalize()}: "
|
|
|
|
display_title += self.draft_title
|
|
|
|
return display_title
|
|
|
|
def get_admin_display_title_html(self):
|
|
return f"""
|
|
<span style="display: inline-flex; align-items: center;">
|
|
<it-icon-checkbox-unchecked style="height: 24px; width: 24px;"></it-icon-checkbox-unchecked>
|
|
<span style="margin-left: 8px;">{self.get_admin_display_title()}</span>
|
|
</span>"""
|
|
|
|
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)
|
|
|
|
@classmethod
|
|
def get_serializer_class(cls):
|
|
return get_it_serializer_class(
|
|
cls,
|
|
field_names=[
|
|
"minutes",
|
|
"contents",
|
|
],
|
|
)
|
|
|
|
def __str__(self):
|
|
return f"{self.title}"
|
|
|
|
|
|
def find_slug_with_parent_prefix(page, type_prefix, slug_postfix=None):
|
|
parent_slug = page.get_ancestors().exact_type(LearningPath, Circle).last().slug
|
|
if parent_slug:
|
|
slug_prefix = f"{parent_slug}-{type_prefix}"
|
|
else:
|
|
slug_prefix = type_prefix
|
|
|
|
if slug_postfix is None:
|
|
slug_postfix = page.title
|
|
|
|
return find_available_slug(
|
|
slugify(f"{slug_prefix}-{slug_postfix}", allow_unicode=True)
|
|
)
|