import graphene from graphene import relay from graphene_django import DjangoObjectType from graphene_django.filter import DjangoFilterConnectionField from api.utils import get_object from users.models import User, Role from ..models import Book, Topic, Module, Chapter, ContentBlock def are_solutions_enabled_for(user: User, module: Module): teacher = user.users_in_same_school_class().filter(user_roles__role=Role.objects.get_default_teacher_role()).first() return teacher is not None and module.solutions_enabled_by.filter(pk=teacher.pk).exists() class ContentBlockNode(DjangoObjectType): mine = graphene.Boolean() 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): if 'users.can_manage_school_class_content' not in info.context.user.get_role_permissions() \ and not are_solutions_enabled_for(info.context.user, self.module): self.contents.stream_data = [content for content in self.contents.stream_data if content['type'] != 'solution'] return self.contents class ChapterNode(DjangoObjectType): content_blocks = DjangoFilterConnectionField(ContentBlockNode) 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') if user.has_perm('users.can_manage_school_class_content'): # teacher publisher_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=False) user_created_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=True, owner=user) else: # student publisher_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=False).exclude( hidden_for__in=school_classes) self_created_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=True, owner=user) user_created_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=True, visible_for__in=school_classes).union( self_created_content_blocks) return publisher_content_blocks.union(user_created_content_blocks) class ModuleNode(DjangoObjectType): pk = graphene.Int() chapters = DjangoFilterConnectionField(ChapterNode) hero_image = graphene.String() solutions_enabled = graphene.Boolean() class Meta: model = Module only_fields = [ 'slug', 'title', 'meta_title', 'teaser', 'intro', 'objective_groups', 'assignments', 'hero_image' ] 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_solutions_enabled(self, info, **kwargs): return self.solutions_enabled_by.filter(pk=info.context.user.pk).exists() def resolve_objective_groups(self, info, **kwargs): user = info.context.user school_classes = user.school_classes.values_list('pk') if user.has_perm('users.can_manage_school_class_content'): # teacher publisher_objective_groups = self.objective_groups.filter(owner=None) user_created_objective_groups = self.objective_groups.filter(owner=user) else: # student publisher_objective_groups = self.objective_groups.filter(owner=None).exclude( hidden_for__in=school_classes) user_created_objective_groups = self.objective_groups.filter(owner__isnull=False, visible_for__in=school_classes) return publisher_objective_groups.union(user_created_objective_groups) class TopicNode(DjangoObjectType): pk = graphene.Int() modules = DjangoFilterConnectionField(ModuleNode) class Meta: model = Topic only_fields = [ 'slug', 'title', 'meta_title', 'teaser', 'description', ] 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 FilteredChapterNode(DjangoObjectType): content_blocks = DjangoFilterConnectionField(ContentBlockNode) class Meta: model = Chapter only_fields = [ 'slug', 'title', ] filter_fields = [ 'slug', 'title', ] interfaces = (relay.Node,) def resolve_content_blocks(self, *args, **kwargs): return ContentBlock.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()) chapter = relay.Node.Field(FilteredChapterNode) content_block = relay.Node.Field(ContentBlockNode) books = DjangoFilterConnectionField(BookNode) topics = DjangoFilterConnectionField(TopicNode) modules = DjangoFilterConnectionField(ModuleNode) chapters = DjangoFilterConnectionField(FilteredChapterNode) 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') if id is not None: return get_object(Module, id) if slug is not None: return Module.objects.get(slug=slug) return None 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