Add new test for school class read only
Also clean up some code
This commit is contained in:
parent
462348dd32
commit
d071afbd67
|
|
@ -24,7 +24,7 @@ class UpdateSolutionVisibility(relay.ClientIDMutation):
|
||||||
slug = args.get('slug')
|
slug = args.get('slug')
|
||||||
enabled = args.get('enabled')
|
enabled = args.get('enabled')
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
selected_class = user.selected_class()
|
selected_class = user.selected_class
|
||||||
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
|
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
|
||||||
raise PermissionError()
|
raise PermissionError()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class ModuleNode(DjangoObjectType):
|
||||||
return self.get_parent().specific
|
return self.get_parent().specific
|
||||||
|
|
||||||
def resolve_solutions_enabled(self, info, **kwargs):
|
def resolve_solutions_enabled(self, info, **kwargs):
|
||||||
school_class = info.context.user.selected_class()
|
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
|
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):
|
def resolve_bookmark(self, info, **kwags):
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.teacher = User.objects.get(username="teacher")
|
self.teacher = User.objects.get(username="teacher")
|
||||||
self.selected_class = self.teacher.selected_class()
|
self.selected_class = self.teacher.selected_class
|
||||||
self.student = User.objects.get(username="student1")
|
self.student = User.objects.get(username="student1")
|
||||||
student_request = RequestFactory().get('/')
|
student_request = RequestFactory().get('/')
|
||||||
student_request.user = self.student
|
student_request.user = self.student
|
||||||
|
|
@ -54,7 +54,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_hide_solutions_for_students_and_then_show_them(self):
|
def test_hide_solutions_for_students_and_then_show_them(self):
|
||||||
self.assertEqual(self.student.selected_class(), self.teacher.selected_class())
|
self.assertEqual(self.student.selected_class, self.teacher.selected_class)
|
||||||
|
|
||||||
student_result = self.student_client.execute(self.query, variables={
|
student_result = self.student_client.execute(self.query, variables={
|
||||||
'id': self.content_block_id
|
'id': self.content_block_id
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from users.models import User
|
||||||
|
|
||||||
|
|
||||||
def are_solutions_enabled_for(user: User, module: Module):
|
def are_solutions_enabled_for(user: User, module: Module):
|
||||||
school_class = user.selected_class()
|
school_class = user.selected_class
|
||||||
return module.solutions_enabled_for.filter(pk=school_class.pk).exists()
|
return module.solutions_enabled_for.filter(pk=school_class.pk).exists()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,6 @@ type CreateTeamPayload {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomMutation {
|
type CustomMutation {
|
||||||
redeemCoupon(input: CouponInput!): CouponPayload
|
|
||||||
spellCheck(input: SpellCheckInput!): SpellCheckPayload
|
spellCheck(input: SpellCheckInput!): SpellCheckPayload
|
||||||
addNote(input: AddNoteInput!): AddNotePayload
|
addNote(input: AddNoteInput!): AddNotePayload
|
||||||
updateNote(input: UpdateNoteInput!): UpdateNotePayload
|
updateNote(input: UpdateNoteInput!): UpdateNotePayload
|
||||||
|
|
@ -920,6 +919,7 @@ type SchoolClassNode implements Node {
|
||||||
rooms(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, appearance: String): RoomNodeConnection!
|
rooms(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, appearance: String): RoomNodeConnection!
|
||||||
pk: Int
|
pk: Int
|
||||||
members: [ClassMemberNode]
|
members: [ClassMemberNode]
|
||||||
|
readOnly: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type SchoolClassNodeConnection {
|
type SchoolClassNodeConnection {
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import AbstractUser, Permission
|
from django.contrib.auth.models import AbstractUser, Permission
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import make_aware, is_aware
|
from django.utils.timezone import make_aware, is_aware
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from users.licenses import MYSKILLBOX_LICENSES
|
from users.licenses import MYSKILLBOX_LICENSES
|
||||||
from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager
|
from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager
|
||||||
|
|
@ -75,7 +77,8 @@ class User(AbstractUser):
|
||||||
def is_teacher(self):
|
def is_teacher(self):
|
||||||
return self.user_roles.filter(role__key='teacher').exists()
|
return self.user_roles.filter(role__key='teacher').exists()
|
||||||
|
|
||||||
def selected_class(self):
|
@cached_property
|
||||||
|
def selected_class(self) -> Union['SchoolClass', None]:
|
||||||
try:
|
try:
|
||||||
settings = UserSetting.objects.get(user=self)
|
settings = UserSetting.objects.get(user=self)
|
||||||
return settings.selected_class
|
return settings.selected_class
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import graphene
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.dateformat import format
|
from django.utils.dateformat import format
|
||||||
from django_filters import FilterSet, OrderingFilter
|
from django_filters import FilterSet, OrderingFilter
|
||||||
from graphene import relay, ObjectType
|
from graphene import ObjectType, relay
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
from graphene_django.filter import DjangoFilterConnectionField
|
from graphene_django.filter import DjangoFilterConnectionField
|
||||||
from graphql_relay import to_global_id
|
from graphql_relay import to_global_id
|
||||||
|
|
@ -13,13 +13,14 @@ from basicknowledge.models import BasicKnowledge
|
||||||
from basicknowledge.queries import InstrumentNode
|
from basicknowledge.queries import InstrumentNode
|
||||||
from books.models import Module
|
from books.models import Module
|
||||||
from books.schema.queries import ModuleNode
|
from books.schema.queries import ModuleNode
|
||||||
from users.models import User, SchoolClass, SchoolClassMember, Team
|
from users.models import SchoolClass, SchoolClassMember, Team, User
|
||||||
|
|
||||||
|
|
||||||
class SchoolClassNode(DjangoObjectType):
|
class SchoolClassNode(DjangoObjectType):
|
||||||
pk = graphene.Int()
|
pk = graphene.Int()
|
||||||
members = graphene.List('users.schema.ClassMemberNode')
|
members = graphene.List('users.schema.ClassMemberNode')
|
||||||
code = graphene.String()
|
code = graphene.String()
|
||||||
|
read_only = graphene.Boolean()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SchoolClass
|
model = SchoolClass
|
||||||
|
|
@ -32,13 +33,19 @@ class SchoolClassNode(DjangoObjectType):
|
||||||
def resolve_members(self, info, **kwargs):
|
def resolve_members(self, info, **kwargs):
|
||||||
return SchoolClassMember.objects.filter(school_class=self)
|
return SchoolClassMember.objects.filter(school_class=self)
|
||||||
|
|
||||||
def resolve_code(self, info, **kwargs):
|
def resolve_code(self: SchoolClass, info, **kwargs):
|
||||||
if not info.context.user.is_teacher():
|
if not info.context.user.is_teacher():
|
||||||
return None
|
return None
|
||||||
if self.code is None:
|
if self.code is None:
|
||||||
self.generate_code()
|
self.generate_code()
|
||||||
return self.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 TeamNode(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -107,25 +114,28 @@ class PrivateUserNode(DjangoObjectType):
|
||||||
def resolve_permissions(self, info):
|
def resolve_permissions(self, info):
|
||||||
return self.get_all_permissions()
|
return self.get_all_permissions()
|
||||||
|
|
||||||
def resolve_selected_class(self, info):
|
@staticmethod
|
||||||
return self.selected_class()
|
def resolve_selected_class(root: User, info):
|
||||||
|
return root.selected_class
|
||||||
|
|
||||||
def resolve_expiry_date(self, info):
|
@staticmethod
|
||||||
if not self.hep_id: # concerns users that already have an (old) account
|
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
|
return format(datetime(2020, 7, 31), 'U') # just set some expiry date
|
||||||
else:
|
else:
|
||||||
return self.license_expiry_date
|
return root.license_expiry_date
|
||||||
|
|
||||||
def resolve_is_teacher(self, info):
|
def resolve_is_teacher(root: User, info):
|
||||||
return self.is_teacher()
|
return root.is_teacher()
|
||||||
|
|
||||||
def resolve_school_classes(self, info):
|
@staticmethod
|
||||||
if self.selected_class() is None: # then we don't have any class to return
|
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.none()
|
||||||
return SchoolClass.objects.filter(
|
return SchoolClass.objects.filter(
|
||||||
Q(schoolclassmember__active=True, schoolclassmember__user=self) | Q(pk=self.selected_class().pk)).distinct()
|
Q(schoolclassmember__active=True, schoolclassmember__user=root) | Q(pk=root.selected_class.pk)).distinct()
|
||||||
|
|
||||||
def resolve_old_classes(self, info):
|
def resolve_old_classes(self: User, info):
|
||||||
return SchoolClass.objects.filter(schoolclassmember__active=False, schoolclassmember__user=self)
|
return SchoolClass.objects.filter(schoolclassmember__active=False, schoolclassmember__user=self)
|
||||||
|
|
||||||
def resolve_recent_modules(self, info, **kwargs):
|
def resolve_recent_modules(self, info, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class JoinSchoolClassTest(TestCase):
|
||||||
self.assertEqual(result['success'], True)
|
self.assertEqual(result['success'], True)
|
||||||
self.assertEqual(result['schoolClass']['name'], 'Klasse 2B')
|
self.assertEqual(result['schoolClass']['name'], 'Klasse 2B')
|
||||||
self.assertEqual(self.user.school_classes.count(), 2)
|
self.assertEqual(self.user.school_classes.count(), 2)
|
||||||
self.assertEqual(self.user.selected_class().code, 'YYYY')
|
self.assertEqual(self.user.selected_class.code, 'YYYY')
|
||||||
|
|
||||||
def test_class_already_joined(self):
|
def test_class_already_joined(self):
|
||||||
code = 'YYYY'
|
code = 'YYYY'
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,5 @@ class MySchoolClasses(TestCase):
|
||||||
self.assertEqual(len(old_classes), 1)
|
self.assertEqual(len(old_classes), 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from graphql_relay import to_global_id
|
||||||
from api.schema import schema
|
from api.schema import schema
|
||||||
from api.utils import get_graphql_mutation, get_object
|
from api.utils import get_graphql_mutation, get_object
|
||||||
from core.factories import UserFactory, TeacherFactory
|
from core.factories import UserFactory, TeacherFactory
|
||||||
|
from core.tests.base_test import SkillboxTestCase
|
||||||
from users.models import SchoolClass, User
|
from users.models import SchoolClass, User
|
||||||
from users.services import create_users
|
from users.services import create_users
|
||||||
|
|
||||||
|
|
@ -38,18 +39,14 @@ class SchoolClassesTest(TestCase):
|
||||||
self.assertEqual(f'{self.prefix} {user.pk}', class_name)
|
self.assertEqual(f'{self.prefix} {user.pk}', class_name)
|
||||||
|
|
||||||
|
|
||||||
class ModifySchoolClassTest(TestCase):
|
class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
create_users()
|
create_users()
|
||||||
self.teacher = User.objects.get(username='teacher')
|
self.teacher = User.objects.get(username='teacher')
|
||||||
self.student = User.objects.get(username='student1')
|
self.student = User.objects.get(username='student1')
|
||||||
|
|
||||||
request = RequestFactory().get('/')
|
self.client = self.get_client(user=self.teacher)
|
||||||
request.user = self.teacher
|
self.student_client = self.get_client(user=self.student)
|
||||||
student_request = RequestFactory().get('/')
|
|
||||||
student_request.user = self.student
|
|
||||||
self.client = Client(schema=schema, context_value=request)
|
|
||||||
self.student_client = Client(schema=schema, context_value=student_request)
|
|
||||||
|
|
||||||
def test_update_school_class(self):
|
def test_update_school_class(self):
|
||||||
class_name = 'The Colbert Show'
|
class_name = 'The Colbert Show'
|
||||||
|
|
@ -115,7 +112,7 @@ class ModifySchoolClassTest(TestCase):
|
||||||
school_class = get_object(SchoolClass, id)
|
school_class = get_object(SchoolClass, id)
|
||||||
self.assertEqual(school_class.name, class_name)
|
self.assertEqual(school_class.name, class_name)
|
||||||
self.assertEqual(school_class.get_teacher(), self.teacher)
|
self.assertEqual(school_class.get_teacher(), self.teacher)
|
||||||
self.assertEqual(self.teacher.selected_class().name, class_name)
|
self.assertEqual(self.teacher.selected_class.name, class_name)
|
||||||
|
|
||||||
def test_create_school_class_fail(self):
|
def test_create_school_class_fail(self):
|
||||||
self.assertEqual(SchoolClass.objects.count(), 2)
|
self.assertEqual(SchoolClass.objects.count(), 2)
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,18 @@
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
|
||||||
from django.test import TestCase, RequestFactory
|
|
||||||
from graphene.test import Client
|
|
||||||
from graphql_relay import to_global_id
|
from graphql_relay import to_global_id
|
||||||
|
|
||||||
from api.schema import schema
|
|
||||||
from core.factories import UserFactory
|
from core.factories import UserFactory
|
||||||
|
from core.tests.base_test import SkillboxTestCase
|
||||||
from users.factories import SchoolClassFactory
|
from users.factories import SchoolClassFactory
|
||||||
from users.models import UserSetting
|
from users.models import SchoolClassMember, UserSetting
|
||||||
|
|
||||||
|
|
||||||
class UserSettingTests(TestCase):
|
class UserSettingTests(SkillboxTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user = UserFactory(username='aschi')
|
self.user = UserFactory(username='aschi')
|
||||||
self.class1 = SchoolClassFactory(users=[self.user])
|
self.class1 = SchoolClassFactory(users=[self.user])
|
||||||
self.class2 = SchoolClassFactory(users=[self.user])
|
self.class2 = SchoolClassFactory(users=[self.user])
|
||||||
self.class3 = SchoolClassFactory(users=[])
|
self.class3 = SchoolClassFactory(users=[])
|
||||||
|
|
||||||
request = RequestFactory().get('/')
|
|
||||||
request.user = self.user
|
|
||||||
|
|
||||||
# adding session
|
|
||||||
middleware = SessionMiddleware()
|
|
||||||
middleware.process_request(request)
|
|
||||||
request.session.save()
|
|
||||||
self.client = Client(schema=schema, context_value=request)
|
|
||||||
|
|
||||||
def make_mutation(self, class_id):
|
def make_mutation(self, class_id):
|
||||||
mutation = '''
|
mutation = '''
|
||||||
|
|
@ -37,7 +26,7 @@ class UserSettingTests(TestCase):
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
return self.client.execute(mutation, variables={
|
return self.get_client(user=self.user).execute(mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'id': to_global_id('SchoolClassNode', class_id)
|
'id': to_global_id('SchoolClassNode', class_id)
|
||||||
}
|
}
|
||||||
|
|
@ -50,18 +39,20 @@ class UserSettingTests(TestCase):
|
||||||
selectedClass {
|
selectedClass {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
|
readOnly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
return self.client.execute(query)
|
return self.get_client(user=self.user).execute(query)
|
||||||
|
|
||||||
def test_selects_first_class_on_first_call(self):
|
def test_selects_first_class_on_first_call(self):
|
||||||
result = self.make_query()
|
result = self.make_query()
|
||||||
first_class = self.user.school_classes.first()
|
first_class = self.user.school_classes.first()
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.get('errors'))
|
||||||
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'), first_class.name)
|
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'), first_class.name)
|
||||||
|
self.assertFalse(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
||||||
|
|
||||||
def test_returns_selected_class(self):
|
def test_returns_selected_class(self):
|
||||||
selected_class = self.user.school_classes.all()[1]
|
selected_class = self.user.school_classes.all()[1]
|
||||||
|
|
@ -73,7 +64,6 @@ class UserSettingTests(TestCase):
|
||||||
selected_class.name)
|
selected_class.name)
|
||||||
|
|
||||||
def test_user_can_select_class(self):
|
def test_user_can_select_class(self):
|
||||||
|
|
||||||
selected_class = self.user.school_classes.first()
|
selected_class = self.user.school_classes.first()
|
||||||
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
||||||
setting.save()
|
setting.save()
|
||||||
|
|
@ -87,7 +77,6 @@ class UserSettingTests(TestCase):
|
||||||
selected_class.name)
|
selected_class.name)
|
||||||
|
|
||||||
def test_user_can_select_class_even_no_settings_exist(self):
|
def test_user_can_select_class_even_no_settings_exist(self):
|
||||||
|
|
||||||
selected_class = self.user.school_classes.all()[1]
|
selected_class = self.user.school_classes.all()[1]
|
||||||
mutation_result = self.make_mutation(selected_class.pk)
|
mutation_result = self.make_mutation(selected_class.pk)
|
||||||
self.assertIsNone(mutation_result.get('errors'))
|
self.assertIsNone(mutation_result.get('errors'))
|
||||||
|
|
@ -106,4 +95,17 @@ class UserSettingTests(TestCase):
|
||||||
mutation_result = self.make_mutation(self.class3.pk)
|
mutation_result = self.make_mutation(self.class3.pk)
|
||||||
self.assertIsNotNone(mutation_result.get('errors'))
|
self.assertIsNotNone(mutation_result.get('errors'))
|
||||||
|
|
||||||
|
def test_inactive_class_as_selected_class(self):
|
||||||
|
selected_class = self.class2
|
||||||
|
membership = SchoolClassMember.objects.get(user=self.user, school_class=selected_class)
|
||||||
|
self.assertTrue(membership.active)
|
||||||
|
membership.active = False
|
||||||
|
membership.save()
|
||||||
|
|
||||||
|
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
||||||
|
setting.save()
|
||||||
|
|
||||||
|
result = self.make_query()
|
||||||
|
self.assertIsNone(result.get('errors'))
|
||||||
|
self.assertTrue(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue