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')
|
||||
enabled = args.get('enabled')
|
||||
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():
|
||||
raise PermissionError()
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class ModuleNode(DjangoObjectType):
|
|||
return self.get_parent().specific
|
||||
|
||||
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
|
||||
|
||||
def resolve_bookmark(self, info, **kwags):
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
)
|
||||
|
||||
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")
|
||||
student_request = RequestFactory().get('/')
|
||||
student_request.user = self.student
|
||||
|
|
@ -54,7 +54,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
"""
|
||||
|
||||
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={
|
||||
'id': self.content_block_id
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from users.models import User
|
|||
|
||||
|
||||
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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -370,7 +370,6 @@ type CreateTeamPayload {
|
|||
}
|
||||
|
||||
type CustomMutation {
|
||||
redeemCoupon(input: CouponInput!): CouponPayload
|
||||
spellCheck(input: SpellCheckInput!): SpellCheckPayload
|
||||
addNote(input: AddNoteInput!): AddNotePayload
|
||||
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!
|
||||
pk: Int
|
||||
members: [ClassMemberNode]
|
||||
readOnly: Boolean
|
||||
}
|
||||
|
||||
type SchoolClassNodeConnection {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ from django.contrib.auth import get_user_model
|
|||
from django.contrib.auth.models import AbstractUser, Permission
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import models
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import make_aware, is_aware
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from typing import Union
|
||||
|
||||
from users.licenses import MYSKILLBOX_LICENSES
|
||||
from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager
|
||||
|
|
@ -75,7 +77,8 @@ class User(AbstractUser):
|
|||
def is_teacher(self):
|
||||
return self.user_roles.filter(role__key='teacher').exists()
|
||||
|
||||
def selected_class(self):
|
||||
@cached_property
|
||||
def selected_class(self) -> Union['SchoolClass', None]:
|
||||
try:
|
||||
settings = UserSetting.objects.get(user=self)
|
||||
return settings.selected_class
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import graphene
|
|||
from django.db.models import Q
|
||||
from django.utils.dateformat import format
|
||||
from django_filters import FilterSet, OrderingFilter
|
||||
from graphene import relay, ObjectType
|
||||
from graphene import ObjectType, relay
|
||||
from graphene_django import DjangoObjectType
|
||||
from graphene_django.filter import DjangoFilterConnectionField
|
||||
from graphql_relay import to_global_id
|
||||
|
|
@ -13,13 +13,14 @@ 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 User, SchoolClass, SchoolClassMember, Team
|
||||
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
|
||||
|
|
@ -32,13 +33,19 @@ class SchoolClassNode(DjangoObjectType):
|
|||
def resolve_members(self, info, **kwargs):
|
||||
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():
|
||||
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:
|
||||
|
|
@ -107,25 +114,28 @@ class PrivateUserNode(DjangoObjectType):
|
|||
def resolve_permissions(self, info):
|
||||
return self.get_all_permissions()
|
||||
|
||||
def resolve_selected_class(self, info):
|
||||
return self.selected_class()
|
||||
@staticmethod
|
||||
def resolve_selected_class(root: User, info):
|
||||
return root.selected_class
|
||||
|
||||
def resolve_expiry_date(self, info):
|
||||
if not self.hep_id: # concerns users that already have an (old) account
|
||||
@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 self.license_expiry_date
|
||||
return root.license_expiry_date
|
||||
|
||||
def resolve_is_teacher(self, info):
|
||||
return self.is_teacher()
|
||||
def resolve_is_teacher(root: User, info):
|
||||
return root.is_teacher()
|
||||
|
||||
def resolve_school_classes(self, info):
|
||||
if self.selected_class() is None: # then we don't have any class to return
|
||||
@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=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)
|
||||
|
||||
def resolve_recent_modules(self, info, **kwargs):
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class JoinSchoolClassTest(TestCase):
|
|||
self.assertEqual(result['success'], True)
|
||||
self.assertEqual(result['schoolClass']['name'], 'Klasse 2B')
|
||||
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):
|
||||
code = 'YYYY'
|
||||
|
|
|
|||
|
|
@ -82,3 +82,5 @@ class MySchoolClasses(TestCase):
|
|||
self.assertEqual(len(old_classes), 1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from graphql_relay import to_global_id
|
|||
from api.schema import schema
|
||||
from api.utils import get_graphql_mutation, get_object
|
||||
from core.factories import UserFactory, TeacherFactory
|
||||
from core.tests.base_test import SkillboxTestCase
|
||||
from users.models import SchoolClass, User
|
||||
from users.services import create_users
|
||||
|
||||
|
|
@ -38,18 +39,14 @@ class SchoolClassesTest(TestCase):
|
|||
self.assertEqual(f'{self.prefix} {user.pk}', class_name)
|
||||
|
||||
|
||||
class ModifySchoolClassTest(TestCase):
|
||||
class ModifySchoolClassTest(SkillboxTestCase):
|
||||
def setUp(self):
|
||||
create_users()
|
||||
self.teacher = User.objects.get(username='teacher')
|
||||
self.student = User.objects.get(username='student1')
|
||||
|
||||
request = RequestFactory().get('/')
|
||||
request.user = self.teacher
|
||||
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)
|
||||
self.client = self.get_client(user=self.teacher)
|
||||
self.student_client = self.get_client(user=self.student)
|
||||
|
||||
def test_update_school_class(self):
|
||||
class_name = 'The Colbert Show'
|
||||
|
|
@ -115,7 +112,7 @@ class ModifySchoolClassTest(TestCase):
|
|||
school_class = get_object(SchoolClass, id)
|
||||
self.assertEqual(school_class.name, class_name)
|
||||
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):
|
||||
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 api.schema import schema
|
||||
from core.factories import UserFactory
|
||||
from core.tests.base_test import SkillboxTestCase
|
||||
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):
|
||||
self.user = UserFactory(username='aschi')
|
||||
self.class1 = SchoolClassFactory(users=[self.user])
|
||||
self.class2 = SchoolClassFactory(users=[self.user])
|
||||
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):
|
||||
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': {
|
||||
'id': to_global_id('SchoolClassNode', class_id)
|
||||
}
|
||||
|
|
@ -50,18 +39,20 @@ class UserSettingTests(TestCase):
|
|||
selectedClass {
|
||||
name
|
||||
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):
|
||||
result = self.make_query()
|
||||
first_class = self.user.school_classes.first()
|
||||
self.assertIsNone(result.get('errors'))
|
||||
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):
|
||||
selected_class = self.user.school_classes.all()[1]
|
||||
|
|
@ -73,7 +64,6 @@ class UserSettingTests(TestCase):
|
|||
selected_class.name)
|
||||
|
||||
def test_user_can_select_class(self):
|
||||
|
||||
selected_class = self.user.school_classes.first()
|
||||
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
||||
setting.save()
|
||||
|
|
@ -87,7 +77,6 @@ class UserSettingTests(TestCase):
|
|||
selected_class.name)
|
||||
|
||||
def test_user_can_select_class_even_no_settings_exist(self):
|
||||
|
||||
selected_class = self.user.school_classes.all()[1]
|
||||
mutation_result = self.make_mutation(selected_class.pk)
|
||||
self.assertIsNone(mutation_result.get('errors'))
|
||||
|
|
@ -106,4 +95,17 @@ class UserSettingTests(TestCase):
|
|||
mutation_result = self.make_mutation(self.class3.pk)
|
||||
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