parent
46d42eb279
commit
3ab0662a6a
|
|
@ -16,11 +16,19 @@
|
|||
>
|
||||
{{ module.title }}
|
||||
</h1>
|
||||
<img
|
||||
:src="module.heroImage"
|
||||
alt=""
|
||||
class="module__hero"
|
||||
/>
|
||||
<div class="module__hero">
|
||||
<img
|
||||
:src="module.heroImage"
|
||||
alt=""
|
||||
class="module__hero-image"
|
||||
/>
|
||||
<h5
|
||||
class="module__hero-source"
|
||||
v-if="module.heroSource"
|
||||
>
|
||||
Quelle: {{ module.heroSource }}
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<div class="module__intro-wrapper">
|
||||
<bookmark-actions
|
||||
|
|
@ -131,8 +139,16 @@ export default {
|
|||
|
||||
&__hero {
|
||||
margin-bottom: 35px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
&__hero-image {
|
||||
max-width: 100%;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
&__hero-source {
|
||||
@include tiny-text;
|
||||
ling-height: 25px;
|
||||
}
|
||||
|
||||
&__meta-title {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,7 @@
|
|||
:src="teaser.imageUrl"
|
||||
class="news-teaser__image"
|
||||
/>
|
||||
<a
|
||||
:href="teaser.imageSource"
|
||||
class="news-teaser__image-source"
|
||||
>Quelle {{ teaser.imageSource }}</a
|
||||
>
|
||||
<h5 class="news-teaser__image-source">Quelle {{ teaser.imageSource }}</h5>
|
||||
|
||||
<h4 class="news-teaser__title">{{ teaser.title }}</h4>
|
||||
<p class="news-teaser__description">{{ teaser.description }}</p>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ fragment ModuleParts on ModuleNode {
|
|||
intro
|
||||
slug
|
||||
heroImage
|
||||
heroSource
|
||||
solutionsEnabled
|
||||
inEditMode @client
|
||||
topic {
|
||||
|
|
|
|||
|
|
@ -11,19 +11,20 @@ from users.models import SchoolClass
|
|||
|
||||
class Module(StrictHierarchyPage):
|
||||
class Meta:
|
||||
verbose_name = 'Modul'
|
||||
verbose_name_plural = 'Module'
|
||||
verbose_name = "Modul"
|
||||
verbose_name_plural = "Module"
|
||||
|
||||
meta_title = models.CharField(
|
||||
max_length=255,
|
||||
help_text='e.g. \'Intro\' or \'Modul 1\''
|
||||
)
|
||||
max_length=255, help_text="e.g. 'Intro' or 'Modul 1'")
|
||||
hero_image = models.ForeignKey(
|
||||
'wagtailimages.Image',
|
||||
"wagtailimages.Image",
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='+'
|
||||
related_name="+",
|
||||
)
|
||||
hero_source = models.CharField(
|
||||
max_length=255, help_text="e.g. 'Reuters', 'Wikipedia'", blank=True
|
||||
)
|
||||
|
||||
teaser = models.TextField()
|
||||
|
|
@ -32,28 +33,26 @@ class Module(StrictHierarchyPage):
|
|||
solutions_enabled_for = models.ManyToManyField(SchoolClass)
|
||||
|
||||
content_panels = [
|
||||
FieldPanel('title', classname="full title"),
|
||||
FieldPanel('meta_title', classname="full title"),
|
||||
ImageChooserPanel('hero_image'),
|
||||
FieldPanel('teaser'),
|
||||
FieldPanel('intro'),
|
||||
FieldPanel("title", classname="full title"),
|
||||
FieldPanel("meta_title", classname="full title"),
|
||||
ImageChooserPanel("hero_image"),
|
||||
FieldPanel("hero_source"),
|
||||
FieldPanel("teaser"),
|
||||
FieldPanel("intro"),
|
||||
]
|
||||
|
||||
edit_handler = TabbedInterface([
|
||||
ObjectList(content_panels, heading='Content'),
|
||||
get_default_settings()
|
||||
])
|
||||
|
||||
template = 'generic_page.html'
|
||||
|
||||
parent_page_types = ['books.Topic']
|
||||
subpage_types = ['books.Chapter']
|
||||
edit_handler = TabbedInterface(
|
||||
[ObjectList(content_panels, heading="Content"), get_default_settings()]
|
||||
)
|
||||
|
||||
template = "generic_page.html"
|
||||
|
||||
parent_page_types = ["books.Topic"]
|
||||
subpage_types = ["books.Chapter"]
|
||||
|
||||
# todo: isn't this a duplicate definition?
|
||||
def get_child_ids(self):
|
||||
return self.get_children().values_list('id', flat=True)
|
||||
return self.get_children().values_list("id", flat=True)
|
||||
|
||||
def sync_from_school_class(self, school_class_template, school_class_to_sync):
|
||||
# import here so we don't get a circular import error
|
||||
|
|
@ -65,41 +64,57 @@ class Module(StrictHierarchyPage):
|
|||
|
||||
# get content blocks of chapters
|
||||
for chapter in chapters:
|
||||
content_block_query = content_block_query.union(ContentBlock.get_by_parent(chapter))
|
||||
content_block_query = content_block_query.union(
|
||||
ContentBlock.get_by_parent(chapter)
|
||||
)
|
||||
|
||||
# clear all `hidden for` and `visible for` for class `school_class_to_sync`
|
||||
for content_block in school_class_to_sync.hidden_content_blocks.intersection(content_block_query):
|
||||
for content_block in school_class_to_sync.hidden_content_blocks.intersection(
|
||||
content_block_query
|
||||
):
|
||||
content_block.hidden_for.remove(school_class_to_sync)
|
||||
for content_block in school_class_to_sync.visible_content_blocks.intersection(content_block_query):
|
||||
for content_block in school_class_to_sync.visible_content_blocks.intersection(
|
||||
content_block_query
|
||||
):
|
||||
content_block.visible_for.remove(school_class_to_sync)
|
||||
|
||||
# get all content blocks with `hidden for` for class `school_class_pattern`
|
||||
for content_block in school_class_template.hidden_content_blocks.intersection(content_block_query):
|
||||
for content_block in school_class_template.hidden_content_blocks.intersection(
|
||||
content_block_query
|
||||
):
|
||||
# add `school_class_to_sync` to these blocks' `hidden for`
|
||||
content_block.hidden_for.add(school_class_to_sync)
|
||||
|
||||
# get all content blocks with `visible for` for class `school_class_pattern`
|
||||
for content_block in school_class_template.visible_content_blocks.intersection(content_block_query):
|
||||
for content_block in school_class_template.visible_content_blocks.intersection(
|
||||
content_block_query
|
||||
):
|
||||
# add `school_class_to_sync` to these blocks' `visible for`
|
||||
content_block.visible_for.add(school_class_to_sync)
|
||||
|
||||
for chapter in chapters:
|
||||
chapter.sync_title_visibility(school_class_template, school_class_to_sync)
|
||||
chapter.sync_description_visibility(school_class_template, school_class_to_sync)
|
||||
chapter.sync_title_visibility(
|
||||
school_class_template, school_class_to_sync)
|
||||
chapter.sync_description_visibility(
|
||||
school_class_template, school_class_to_sync
|
||||
)
|
||||
|
||||
objective_groups = self.objective_groups.all()
|
||||
|
||||
for objective_group in objective_groups:
|
||||
objective_group.sync_visibility(school_class_template, school_class_to_sync)
|
||||
objective_group.sync_visibility(
|
||||
school_class_template, school_class_to_sync)
|
||||
|
||||
def get_admin_display_title(self):
|
||||
return f"{self.meta_title} - {self.title}"
|
||||
|
||||
|
||||
class RecentModule(models.Model):
|
||||
module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='recent_modules')
|
||||
user = models.ForeignKey('users.User', on_delete=models.CASCADE)
|
||||
module = models.ForeignKey(
|
||||
Module, on_delete=models.CASCADE, related_name="recent_modules"
|
||||
)
|
||||
user = models.ForeignKey("users.User", on_delete=models.CASCADE)
|
||||
visited = models.DateTimeField(default=timezone.now)
|
||||
|
||||
class Meta:
|
||||
get_latest_by = 'visited'
|
||||
get_latest_by = "visited"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,11 @@ from books.models import Module, Chapter, ContentBlock, RecentModule
|
|||
from books.schema.interfaces.module import ModuleInterface
|
||||
from books.schema.nodes.chapter import ChapterNode
|
||||
from notes.models import ModuleBookmark, ContentBlockBookmark, ChapterBookmark
|
||||
from notes.schema import ModuleBookmarkNode, ContentBlockBookmarkNode, ChapterBookmarkNode
|
||||
from notes.schema import (
|
||||
ModuleBookmarkNode,
|
||||
ContentBlockBookmarkNode,
|
||||
ChapterBookmarkNode,
|
||||
)
|
||||
from objectives.schema import ObjectiveGroupNode
|
||||
from surveys.models import Answer
|
||||
from surveys.schema import AnswerNode
|
||||
|
|
@ -20,11 +24,20 @@ class ModuleNode(DjangoObjectType):
|
|||
class Meta:
|
||||
model = Module
|
||||
only_fields = [
|
||||
'slug', 'title', 'meta_title', 'teaser', 'intro', 'objective_groups', 'assignments', 'hero_image', 'topic'
|
||||
"slug",
|
||||
"title",
|
||||
"meta_title",
|
||||
"teaser",
|
||||
"intro",
|
||||
"objective_groups",
|
||||
"assignments",
|
||||
"hero_image",
|
||||
"hero_source",
|
||||
"topic",
|
||||
]
|
||||
filter_fields = {
|
||||
'slug': ['exact', 'icontains', 'in'],
|
||||
'title': ['exact', 'icontains', 'in'],
|
||||
"slug": ["exact", "icontains", "in"],
|
||||
"title": ["exact", "icontains", "in"],
|
||||
}
|
||||
interfaces = (ModuleInterface,)
|
||||
|
||||
|
|
@ -33,9 +46,10 @@ class ModuleNode(DjangoObjectType):
|
|||
bookmark = graphene.Field(ModuleBookmarkNode)
|
||||
my_submissions = DjangoFilterConnectionField(StudentSubmissionNode)
|
||||
my_answers = DjangoFilterConnectionField(AnswerNode)
|
||||
my_content_bookmarks = DjangoFilterConnectionField(ContentBlockBookmarkNode)
|
||||
my_content_bookmarks = DjangoFilterConnectionField(
|
||||
ContentBlockBookmarkNode)
|
||||
my_chapter_bookmarks = DjangoFilterConnectionField(ChapterBookmarkNode)
|
||||
snapshots = graphene.List('books.schema.nodes.SnapshotNode')
|
||||
snapshots = graphene.List("books.schema.nodes.SnapshotNode")
|
||||
objective_groups = graphene.List(ObjectiveGroupNode)
|
||||
assignments = graphene.List(AssignmentNode)
|
||||
|
||||
|
|
@ -47,12 +61,15 @@ class ModuleNode(DjangoObjectType):
|
|||
|
||||
def resolve_solutions_enabled(self, info, **kwargs):
|
||||
school_class = info.context.user.selected_class
|
||||
return self.solutions_enabled_for.filter(pk=school_class.pk).exists() if school_class is not None else False
|
||||
return (
|
||||
self.solutions_enabled_for.filter(pk=school_class.pk).exists()
|
||||
if school_class is not None
|
||||
else False
|
||||
)
|
||||
|
||||
def resolve_bookmark(self, info, **kwags):
|
||||
return ModuleBookmark.objects.filter(
|
||||
user=info.context.user,
|
||||
module=self
|
||||
user=info.context.user, module=self
|
||||
).first()
|
||||
|
||||
def resolve_my_submissions(self, info, **kwargs):
|
||||
|
|
@ -69,7 +86,9 @@ class ModuleNode(DjangoObjectType):
|
|||
def resolve_my_content_bookmarks(self, info, **kwargs):
|
||||
user = info.context.user
|
||||
content_blocks = ContentBlock.objects.live().descendant_of(self)
|
||||
return ContentBlockBookmark.objects.filter(content_block__in=content_blocks, user=user)
|
||||
return ContentBlockBookmark.objects.filter(
|
||||
content_block__in=content_blocks, user=user
|
||||
)
|
||||
# Bookmark Text
|
||||
# Bookmark Image etc
|
||||
# Bookmark Other
|
||||
|
|
@ -83,13 +102,14 @@ class ModuleNode(DjangoObjectType):
|
|||
|
||||
@staticmethod
|
||||
def resolve_objective_groups(parent, info, **kwargs):
|
||||
return parent.objective_groups.all() \
|
||||
.prefetch_related('hidden_for')
|
||||
return parent.objective_groups.all().prefetch_related("hidden_for")
|
||||
|
||||
@staticmethod
|
||||
def resolve_snapshots(parent, info, **kwargs):
|
||||
user = info.context.user
|
||||
return parent.snapshots.filter(Q(creator=user) | Q(Q(creator__team=user.team ) & Q(shared=True)))
|
||||
return parent.snapshots.filter(
|
||||
Q(creator=user) | Q(Q(creator__team=user.team) & Q(shared=True))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def resolve_assignments(parent: Module, info, **kwargs):
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ type ChapterNode implements Node & ChapterInterface {
|
|||
id: ID!
|
||||
bookmark: ChapterBookmarkNode
|
||||
contentBlocks: [ContentBlockNode]
|
||||
path: String
|
||||
}
|
||||
|
||||
type ChapterNodeConnection {
|
||||
|
|
@ -621,6 +622,7 @@ type ModuleNode implements ModuleInterface {
|
|||
slug: String!
|
||||
metaTitle: String!
|
||||
heroImage: String!
|
||||
heroSource: String!
|
||||
teaser: String!
|
||||
intro: String!
|
||||
assignments: [AssignmentNode]
|
||||
|
|
|
|||
Loading…
Reference in New Issue