import graphene from django.db.models import Q from graphene import relay from graphene_django import DjangoObjectType from graphene_django.filter import DjangoFilterConnectionField from api.utils import get_object from assignments.models import StudentSubmission from assignments.schema.types import StudentSubmissionNode from books.utils import are_solutions_enabled_for 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 from ..models import Book, Topic, Module, Chapter, ContentBlock 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 class ContentBlockNode(DjangoObjectType): mine = graphene.Boolean() bookmarks = graphene.List(ContentBlockBookmarkNode) 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: if content['type'] == 'solution' and not are_solutions_enabled_for(info.context.user, self.module): 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', ] 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) else: # student return by_parent.filter(default_blocks | teacher_created_and_visible) def resolve_bookmark(self, info, **kwags): 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): teacher = info.context.user.get_teacher() return self.solutions_enabled_by.filter(pk=teacher.pk).exists() if teacher 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') \ .prefetch_related('visible_for') \ .prefetch_related('objectives__objective_progress') class TopicNode(DjangoObjectType): pk = graphene.Int() modules = DjangoFilterConnectionField(ModuleNode) class Meta: model = Topic only_fields = [ 'slug', 'title', 'meta_title', 'teaser', 'description', 'vimeo_id', 'order' ] 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) class BookQuery(object): book = relay.Node.Field(BookNode) topic = graphene.Field(TopicNode, slug=graphene.String()) module = graphene.Field(ModuleNode, slug=graphene.String(), id=graphene.ID()) chapter = relay.Node.Field(ChapterNode) content_block = relay.Node.Field(ContentBlockNode) books = DjangoFilterConnectionField(BookNode) topics = DjangoFilterConnectionField(TopicNode) modules = DjangoFilterConnectionField(ModuleNode) chapters = DjangoFilterConnectionField(ChapterNode) def resolve_books(self, *args, **kwargs): return Book.objects.filter(**kwargs).live() def resolve_topics(self, *args, **kwargs): return Topic.objects.filter(**kwargs).live() def resolve_modules(self, *args, **kwargs): return Module.objects.filter(**kwargs).live() def resolve_chapters(self, *args, **kwargs): return Chapter.objects.filter(**kwargs).live() def resolve_module(self, info, **kwargs): slug = kwargs.get('slug') id = kwargs.get('id') module = None if id is not None: module = get_object(Module, id) elif slug is not None: module = Module.objects.get(slug=slug) return module def resolve_topic(self, info, **kwargs): slug = kwargs.get('slug') id = kwargs.get('id') if id is not None: return get_object(Topic, id) if slug is not None: return Topic.objects.get(slug=slug) return None