Refactor module server code
This commit is contained in:
parent
da2253a73d
commit
85706d73d1
|
|
@ -428,7 +428,7 @@ type CustomQuery {
|
|||
chapter(id: ID!): ChapterNode
|
||||
contentBlock(id: ID!): ContentBlockNode
|
||||
books(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): BookNodeConnection
|
||||
topics(before: String, after: String, first: Int, last: Int): TopicConnection
|
||||
topics(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): TopicNodeConnection
|
||||
modules(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection
|
||||
chapters(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, title: String): ChapterNodeConnection
|
||||
objectiveGroup(id: ID!): ObjectiveGroupNode
|
||||
|
|
@ -955,16 +955,6 @@ type TeamNode implements Node {
|
|||
pk: Int
|
||||
}
|
||||
|
||||
type TopicConnection {
|
||||
pageInfo: PageInfo!
|
||||
edges: [TopicEdge]!
|
||||
}
|
||||
|
||||
type TopicEdge {
|
||||
node: TopicNode
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type TopicNode implements Node {
|
||||
title: String!
|
||||
slug: String!
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
import graphene
|
||||
from graphene import relay
|
||||
|
||||
from books.schema.nodes import ModuleNode, TopicNode
|
||||
|
||||
|
||||
class NodeConnection(relay.Connection):
|
||||
"""
|
||||
Custom connection type, so we don't need to deal with the edges and nodes if we don't want to, while still
|
||||
adhering to the relay specification
|
||||
Idea from: https://javascript.plainenglish.io/graphql-pagination-using-edges-vs-nodes-in-connections-f2ddb8edffa0
|
||||
|
||||
Always has property called `nodes` which is filled with the Meta node class.
|
||||
|
||||
Example:
|
||||
class TopicConnection(NodeConnection):
|
||||
class Meta:
|
||||
node = TopicNode
|
||||
# will have
|
||||
# nodes = graphene.List(TopicNode)
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def resolve_nodes(self, *args, **kwargs):
|
||||
return [edge.node for edge in self.edges]
|
||||
|
||||
@classmethod
|
||||
def __init_subclass_with_meta__(cls, node=None, name=None, **options):
|
||||
cls.nodes = graphene.List(node)
|
||||
return super().__init_subclass_with_meta__(
|
||||
node, name, **options
|
||||
)
|
||||
|
||||
|
||||
class TopicConnection(NodeConnection):
|
||||
class Meta:
|
||||
node = TopicNode
|
||||
|
||||
|
||||
class ModuleConnection(NodeConnection):
|
||||
class Meta:
|
||||
node = ModuleNode
|
||||
|
|
@ -4,7 +4,7 @@ from graphene import relay
|
|||
from api.utils import get_object
|
||||
from books.models import Chapter
|
||||
from books.schema.inputs import UserGroupBlockVisibility
|
||||
from books.schema.queries import ChapterNode
|
||||
from books.schema.nodes import ChapterNode
|
||||
from users.models import SchoolClass
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from graphql_relay import from_global_id
|
|||
from api.utils import get_object, get_errors
|
||||
from books.models import ContentBlock, Chapter, SchoolClass
|
||||
from books.schema.inputs import ContentBlockInput
|
||||
from books.schema.queries import ContentBlockNode
|
||||
from ..nodes import ContentBlockNode
|
||||
from core.utils import set_hidden_for, set_visible_for
|
||||
from .utils import handle_content_block, set_user_defined_block_type
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from graphene import relay
|
|||
|
||||
from api.utils import get_object
|
||||
from books.models import Module, RecentModule
|
||||
from books.schema.queries import ModuleNode
|
||||
from books.schema.nodes import ModuleNode
|
||||
from users.models import SchoolClass
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from graphene import relay
|
|||
|
||||
from api.utils import get_object
|
||||
from books.models import Topic
|
||||
from books.schema.queries import TopicNode
|
||||
from books.schema.nodes import TopicNode
|
||||
|
||||
|
||||
class UpdateLastTopic(relay.ClientIDMutation):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,260 @@
|
|||
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
|
||||
|
|
@ -1,244 +1,15 @@
|
|||
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, RecentModule
|
||||
from core.logger import get_logger
|
||||
|
||||
from ..models import Book, Topic, Module, Chapter
|
||||
from .nodes import ContentBlockNode, ChapterNode, ModuleNode, TopicNode, BookNode
|
||||
from .connections import TopicConnection, ModuleConnection
|
||||
|
||||
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:
|
||||
# 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()):
|
||||
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, **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):
|
||||
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)
|
||||
|
||||
|
||||
class TopicConnection(relay.Connection):
|
||||
class Meta:
|
||||
node = TopicNode
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class BookQuery(object):
|
||||
|
|
@ -250,7 +21,9 @@ class BookQuery(object):
|
|||
content_block = relay.Node.Field(ContentBlockNode)
|
||||
|
||||
books = DjangoFilterConnectionField(BookNode)
|
||||
topics = relay.ConnectionField(TopicConnection)
|
||||
topics = DjangoFilterConnectionField(TopicNode)
|
||||
# topics = relay.ConnectionField(TopicConnection)
|
||||
# modules = relay.ConnectionField(ModuleConnection)
|
||||
modules = DjangoFilterConnectionField(ModuleNode)
|
||||
chapters = DjangoFilterConnectionField(ChapterNode)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue