skillbox/server/books/schema/nodes.py

261 lines
8.7 KiB
Python

import graphene
from django.db.models import Q
from graphene import relay
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField
from assignments.models import StudentSubmission
from assignments.schema.types import StudentSubmissionNode
from books.models import ContentBlock, Chapter, Module, RecentModule, Topic, Book
from books.utils import are_solutions_enabled_for
from core.logger import get_logger
from notes.models import ContentBlockBookmark, ChapterBookmark, ModuleBookmark
from notes.schema import ContentBlockBookmarkNode, ChapterBookmarkNode, ModuleBookmarkNode
from rooms.models import ModuleRoomSlug
from surveys.models import Answer
from surveys.schema import AnswerNode
logger = get_logger(__name__)
class TextBlockNode(graphene.ObjectType):
text = graphene.String()
def resolve_text(root, info, **kwargs):
return root['value']['text']
class ContentNode(graphene.Union):
class Meta:
types = (TextBlockNode,)
@classmethod
def resolve_type(cls, instance, info):
logger.info(instance)
if instance['type'] == 'text_block':
return TextBlockNode
class ContentBlockNode(DjangoObjectType):
mine = graphene.Boolean()
bookmarks = graphene.List(ContentBlockBookmarkNode)
# contents = graphene.List(ContentNode)
class Meta:
model = ContentBlock
only_fields = [
'slug', 'title', 'type', 'contents', 'hidden_for', 'visible_for', 'user_created'
]
filter_fields = [
'slug', 'title',
]
interfaces = (relay.Node,)
def resolve_mine(self, info, **kwargs):
return self.owner is not None and self.owner.pk == info.context.user.pk
def resolve_contents(self, info, **kwargs):
updated_stream_data = []
for content in self.contents.stream_data:
# only show solutions to teachers and students for whom their teachers have them enabled
if content['type'] == 'solution' \
and not (are_solutions_enabled_for(info.context.user, self.module) or info.context.user.is_teacher()):
logger.debug('Solution is hidden for this user')
continue
if content['type'] == 'content_list_item':
for index, list_block in enumerate(content['value']):
content['value'][index] = process_module_room_slug_block(list_block)
content = process_module_room_slug_block(content)
updated_stream_data.append(content)
self.contents.stream_data = updated_stream_data
return self.contents
def resolve_bookmarks(self, info, **kwargs):
return ContentBlockBookmark.objects.filter(
user=info.context.user,
content_block=self
)
class ChapterNode(DjangoObjectType):
content_blocks = DjangoFilterConnectionField(ContentBlockNode)
bookmark = graphene.Field(ChapterBookmarkNode)
class Meta:
model = Chapter
only_fields = [
'slug', 'title', 'description', 'title_hidden_for', 'description_hidden_for'
]
filter_fields = [
'slug', 'title',
]
interfaces = (relay.Node,)
def resolve_content_blocks(self, info, **kwargs):
user = info.context.user
school_classes = user.school_classes.values_list('pk')
by_parent = ContentBlock.get_by_parent(self) \
.prefetch_related('visible_for') \
.prefetch_related('hidden_for')
# don't filter the hidden blocks on the server any more, we do this on the client now, as they are not secret
default_blocks = Q(user_created=False)
owned_by_user = Q(user_created=True, owner=user)
teacher_created_and_visible = Q(Q(user_created=True) & Q(visible_for__in=school_classes))
if user.has_perm('users.can_manage_school_class_content'): # teacher
return by_parent.filter(default_blocks | owned_by_user | teacher_created_and_visible).distinct()
else: # student
return by_parent.filter(default_blocks | teacher_created_and_visible).distinct()
def resolve_bookmark(self, info, **kwargs):
return ChapterBookmark.objects.filter(
user=info.context.user,
chapter=self
).first()
class ModuleNode(DjangoObjectType):
pk = graphene.Int()
chapters = DjangoFilterConnectionField(ChapterNode)
topic = graphene.Field('books.schema.queries.TopicNode')
hero_image = graphene.String()
solutions_enabled = graphene.Boolean()
bookmark = graphene.Field(ModuleBookmarkNode)
my_submissions = DjangoFilterConnectionField(StudentSubmissionNode)
my_answers = DjangoFilterConnectionField(AnswerNode)
my_content_bookmarks = DjangoFilterConnectionField(ContentBlockBookmarkNode)
my_chapter_bookmarks = DjangoFilterConnectionField(ChapterBookmarkNode)
class Meta:
model = Module
only_fields = [
'slug', 'title', 'meta_title', 'teaser', 'intro', 'objective_groups', 'assignments', 'hero_image', 'topic'
]
filter_fields = {
'slug': ['exact', 'icontains', 'in'],
'title': ['exact', 'icontains', 'in'],
}
interfaces = (relay.Node,)
def resolve_pk(self, info, **kwargs):
return self.id
def resolve_hero_image(self, info, **kwargs):
if self.hero_image:
return self.hero_image.file.url
def resolve_chapters(self, info, **kwargs):
return Chapter.get_by_parent(self)
def resolve_topic(self, info, **kwargs):
return self.get_parent().specific
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
def resolve_bookmark(self, info, **kwags):
return ModuleBookmark.objects.filter(
user=info.context.user,
module=self
).first()
def resolve_my_submissions(self, info, **kwargs):
user = info.context.user
return StudentSubmission.objects.filter(student=user, assignment__module=self)
# we want:
# StudentSubmission
def resolve_my_answers(self, info, **kwargs):
user = info.context.user
return Answer.objects.filter(owner=user, survey__module=self)
# Survey
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)
# Bookmark Text
# Bookmark Image etc
# Bookmark Other
# Note
#
def resolve_my_chapter_bookmarks(self, info, **kwargs):
user = info.context.user
chapters = Chapter.objects.live().descendant_of(self)
return ChapterBookmark.objects.filter(chapter__in=chapters, user=user)
def resolve_objective_groups(self, root, **kwargs):
return self.objective_groups.all() \
.prefetch_related('hidden_for')
class RecentModuleNode(DjangoObjectType):
class Meta:
model = RecentModule
interfaces = (relay.Node,)
class TopicNode(DjangoObjectType):
pk = graphene.Int()
modules = DjangoFilterConnectionField(ModuleNode)
class Meta:
model = Topic
only_fields = [
'slug', 'title', 'teaser', 'description', 'vimeo_id', 'order', 'instructions'
]
filter_fields = {
'slug': ['exact', 'icontains', 'in'],
'title': ['exact', 'icontains', 'in'],
}
interfaces = (relay.Node,)
def resolve_pk(self, *args, **kwargs):
return self.id
def resolve_modules(self, *args, **kwargs):
return Module.get_by_parent(self)
class BookNode(DjangoObjectType):
pk = graphene.Int()
topics = DjangoFilterConnectionField(TopicNode)
class Meta:
model = Book
only_fields = [
'slug', 'title',
]
filter_fields = {
'slug': ['exact', 'icontains', 'in'],
'title': ['exact', 'icontains', 'in'],
}
interfaces = (relay.Node,)
def resolve_pk(self, *args, **kwargs):
return self.id
def resolve_topics(self, *args, **kwargs):
return Topic.get_by_parent(self)
def process_module_room_slug_block(content):
if content['type'] == 'module_room_slug':
try:
module_room_slug = ModuleRoomSlug.objects.get(title=content['value']['title'])
content['value'] = {
'title': content['value']['title'],
'slug': module_room_slug.slug
}
except ModuleRoomSlug.DoesNotExist:
pass
return content