from django.db import models
from django.utils.text import slugify
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
from wagtail.blocks import StreamBlock
from wagtail.fields import RichTextField, StreamField
from wagtail.models import Page
from vbv_lernwelt.core.model_utils import find_available_slug
from vbv_lernwelt.course.models import CourseBasePage, CoursePage
from vbv_lernwelt.learnpath.models_learning_unit_content import (
AssignmentBlock,
BookBlock,
DocumentBlock,
ExerciseBlock,
FeedbackBlock,
LearningModuleBlock,
MediaLibraryBlock,
OnlineTrainingBlock,
PlaceholderBlock,
ResourceBlock,
TestBlock,
VideoBlock,
)
class LearningPath(CourseBasePage):
serialize_field_names = ["children", "course"]
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"/course/{self.get_parent().slug}/learn"
class Topic(CourseBasePage):
serialize_field_names = ["is_visible"]
is_visible = models.BooleanField(default=True)
parent_page_types = ["learnpath.LearningPath"]
panels = [
FieldPanel("title"),
FieldPanel("is_visible"),
]
def full_clean(self, *args, **kwargs):
self.slug = find_slug_with_parent_prefix(self, "topic")
super(Topic, self).full_clean(*args, **kwargs)
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 Circle(CourseBasePage):
parent_page_types = ["learnpath.LearningPath"]
subpage_types = [
"learnpath.LearningSequence",
"learnpath.LearningUnit",
"learnpath.LearningContent",
]
serialize_field_names = [
"children",
"description",
"goals",
]
description = models.TextField(default="", blank=True)
goals = RichTextField()
content_panels = Page.content_panels + [
FieldPanel("description"),
FieldPanel("goals"),
]
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(CourseBasePage):
serialize_field_names = ["icon"]
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}"
def get_admin_display_title(self):
return f"{self.icon} {self.draft_title}"
def get_admin_display_title_html(self):
return f"""
<{self.icon} style="height: 32px; width: 32px;">{self.icon}>
{self.draft_title}
"""
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(CourseBasePage):
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()}#lu-{short_slug}"
def get_evaluate_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'{self.draft_title}'
class LearningContent(CourseBasePage):
serialize_field_names = [
"minutes",
"contents",
]
parent_page_types = ["learnpath.Circle"]
subpage_types = []
minutes = models.PositiveIntegerField(default=15)
content_blocks = [
("video", VideoBlock()),
("resource", ResourceBlock()),
("exercise", ExerciseBlock()),
("learningmodule", LearningModuleBlock()),
("online_training", OnlineTrainingBlock()),
("media_library", MediaLibraryBlock()),
("document", DocumentBlock()),
("test", TestBlock()),
("book", BookBlock()),
("assignment", AssignmentBlock()),
("placeholder", PlaceholderBlock()),
("feedback", FeedbackBlock()),
]
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"""
{self.get_admin_display_title()}
"""
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)
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)
)