217 lines
6.8 KiB
Python
217 lines
6.8 KiB
Python
from datetime import datetime
|
|
|
|
import graphene
|
|
from django.db.models import Q
|
|
from django.utils.dateformat import format
|
|
from django_filters import FilterSet, OrderingFilter
|
|
from graphene import ObjectType, relay
|
|
from graphene_django import DjangoObjectType
|
|
from graphene_django.filter import DjangoFilterConnectionField
|
|
from graphql_relay import to_global_id
|
|
|
|
from basicknowledge.models import BasicKnowledge
|
|
from basicknowledge.queries import InstrumentNode
|
|
from books.models import Module
|
|
from books.schema.queries import ModuleNode
|
|
from users.models import SchoolClass, SchoolClassMember, Team, User
|
|
|
|
|
|
class SchoolClassNode(DjangoObjectType):
|
|
pk = graphene.Int()
|
|
members = graphene.List('users.schema.ClassMemberNode')
|
|
code = graphene.String()
|
|
read_only = graphene.Boolean()
|
|
|
|
class Meta:
|
|
model = SchoolClass
|
|
only_fields = ['name', 'code', 'members', 'pk', 'read_only']
|
|
filter_fields = ['name']
|
|
interfaces = (relay.Node,)
|
|
|
|
def resolve_pk(self, *args, **kwargs):
|
|
return self.id
|
|
|
|
def resolve_members(self, info, **kwargs):
|
|
return SchoolClassMember.objects.filter(school_class=self)
|
|
|
|
def resolve_code(self: SchoolClass, info, **kwargs):
|
|
if not info.context.user.is_teacher():
|
|
return None
|
|
if self.code is None:
|
|
self.generate_code()
|
|
return self.code
|
|
|
|
@staticmethod
|
|
def resolve_read_only(root: SchoolClass, info, **kwargs):
|
|
user = info.context.user
|
|
member = SchoolClassMember.objects.get(user=user, school_class=root)
|
|
return not member.active
|
|
|
|
|
|
class TeamNode(DjangoObjectType):
|
|
class Meta:
|
|
model = Team
|
|
filter_fields = ['name']
|
|
interfaces = (relay.Node,)
|
|
|
|
pk = graphene.Int()
|
|
members = graphene.List('users.schema.PublicUserNode')
|
|
|
|
def resolve_pk(self, *args, **kwargs):
|
|
return self.id
|
|
|
|
def resolve_members(self, *args, **kwargs):
|
|
return self.members.all()
|
|
|
|
|
|
class RecentModuleFilter(FilterSet):
|
|
class Meta:
|
|
model = Module
|
|
fields = ('recent_modules',)
|
|
|
|
order_by = OrderingFilter(
|
|
fields=(
|
|
('recent_modules__visited', 'visited'),
|
|
)
|
|
)
|
|
|
|
|
|
class PublicUserNode(DjangoObjectType):
|
|
full_name = graphene.String(required=True)
|
|
is_me = graphene.Boolean()
|
|
|
|
class Meta:
|
|
model = User
|
|
only_fields = ['full_name', 'first_name', 'last_name', 'avatar_url']
|
|
interfaces = (relay.Node,)
|
|
|
|
@staticmethod
|
|
def resolve_is_me(parent: User, info, **kwargs):
|
|
return info.context.user.pk == parent.pk
|
|
|
|
|
|
class PrivateUserNode(DjangoObjectType):
|
|
class Meta:
|
|
model = User
|
|
filter_fields = ['username', 'email']
|
|
only_fields = ['username', 'email', 'first_name', 'last_name', 'school_classes', 'last_module',
|
|
'last_topic', 'avatar_url',
|
|
'selected_class', 'expiry_date', 'onboarding_visited', 'team', 'read_only']
|
|
interfaces = (relay.Node,)
|
|
|
|
pk = graphene.Int()
|
|
permissions = graphene.List(graphene.String)
|
|
selected_class = graphene.Field(SchoolClassNode)
|
|
expiry_date = graphene.String()
|
|
is_teacher = graphene.Boolean()
|
|
old_classes = DjangoFilterConnectionField(SchoolClassNode)
|
|
recent_modules = DjangoFilterConnectionField(ModuleNode, filterset_class=RecentModuleFilter)
|
|
team = graphene.Field(TeamNode)
|
|
read_only = graphene.Boolean()
|
|
|
|
def resolve_pk(self, info, **kwargs):
|
|
return self.id
|
|
|
|
def resolve_permissions(self, info):
|
|
return self.get_all_permissions()
|
|
|
|
@staticmethod
|
|
def resolve_selected_class(root: User, info):
|
|
return root.selected_class
|
|
|
|
@staticmethod
|
|
def resolve_expiry_date(root: User, info):
|
|
if not root.hep_id: # concerns users that already have an (old) account
|
|
return format(datetime(2020, 7, 31), 'U') # just set some expiry date
|
|
else:
|
|
return root.license_expiry_date
|
|
|
|
def resolve_is_teacher(root: User, info):
|
|
return root.is_teacher()
|
|
|
|
@staticmethod
|
|
def resolve_school_classes(root: User, info):
|
|
if root.selected_class is None: # then we don't have any class to return
|
|
return SchoolClass.objects.none()
|
|
return SchoolClass.objects.filter(
|
|
Q(schoolclassmember__active=True, schoolclassmember__user=root) | Q(pk=root.selected_class.pk)).distinct()
|
|
|
|
def resolve_old_classes(self: User, info):
|
|
return SchoolClass.objects.filter(schoolclassmember__active=False, schoolclassmember__user=self)
|
|
|
|
def resolve_recent_modules(self, info, **kwargs):
|
|
# see https://docs.graphene-python.org/projects/django/en/latest/filtering/
|
|
return RecentModuleFilter(kwargs).qs.filter(recent_modules__user=self)
|
|
|
|
def resolve_team(self, info, **kwargs):
|
|
return self.team
|
|
|
|
|
|
class ClassMemberNode(ObjectType):
|
|
"""
|
|
We need to build this ourselves, because we want the active property on the node, because providing it on the
|
|
Connection or Edge for a UserNodeConnection is difficult.
|
|
"""
|
|
user = graphene.Field('users.schema.PublicUserNode')
|
|
active = graphene.Boolean()
|
|
first_name = graphene.String()
|
|
last_name = graphene.String()
|
|
is_teacher = graphene.Boolean()
|
|
id = graphene.ID()
|
|
is_me = graphene.Boolean()
|
|
|
|
def resolve_id(self, *args):
|
|
return to_global_id('PublicUserNode', self.user.pk)
|
|
|
|
def resolve_active(self, *args):
|
|
return self.active
|
|
|
|
def resolve_first_name(self, *args):
|
|
return self.user.first_name
|
|
|
|
def resolve_last_name(self, *args):
|
|
return self.user.last_name
|
|
|
|
def resolve_user(self, info, **kwargs):
|
|
return self.user
|
|
|
|
def resolve_is_teacher(self, *args):
|
|
return self.user.is_teacher()
|
|
|
|
@staticmethod
|
|
def resolve_is_me(parent, info, **kwargs):
|
|
return info.context.user.pk == parent.user.pk
|
|
|
|
|
|
class UsersQuery(object):
|
|
me = graphene.Field(PrivateUserNode)
|
|
all_users = DjangoFilterConnectionField(PrivateUserNode)
|
|
my_activity = DjangoFilterConnectionField(ModuleNode)
|
|
my_instrument_activity = DjangoFilterConnectionField(InstrumentNode)
|
|
|
|
def resolve_me(self, info, **kwargs):
|
|
return info.context.user
|
|
|
|
def resolve_all_users(self, info, **kwargs):
|
|
if not info.context.user.is_superuser:
|
|
return User.objects.none()
|
|
else:
|
|
return User.objects.all()
|
|
|
|
def resolve_my_activity(self, info, **kwargs):
|
|
return Module.objects.all()
|
|
|
|
def resolve_my_instrument_activity(self, info, **kwargs):
|
|
return BasicKnowledge.objects.all()
|
|
|
|
|
|
class AllUsersQuery(object):
|
|
me = graphene.Field(PrivateUserNode)
|
|
all_users = DjangoFilterConnectionField(PrivateUserNode)
|
|
|
|
def resolve_all_users(self, info, **kwargs):
|
|
if not info.context.user.is_superuser:
|
|
return User.objects.none()
|
|
else:
|
|
return User.objects.all()
|