Add update team mutation on server and some tests for it

This commit is contained in:
Ramon Wenger 2021-03-25 18:00:04 +01:00
parent b84aa50443
commit 9bde5dbb20
3 changed files with 116 additions and 49 deletions

View File

@ -6,11 +6,13 @@ from graphene import relay
from graphql_relay import from_global_id from graphql_relay import from_global_id
from api.utils import get_object from api.utils import get_object
from core.logger import get_logger
from users.inputs import PasswordUpdateInput from users.inputs import PasswordUpdateInput
from users.models import SchoolClass, SchoolClassMember, Team from users.models import SchoolClass, SchoolClassMember, Team
from users.schema import SchoolClassNode, TeamNode from users.schema import SchoolClassNode, TeamNode
from users.serializers import PasswordSerialzer, AvatarUrlSerializer from users.serializers import PasswordSerialzer, AvatarUrlSerializer
logger = get_logger(__name__)
class CodeNotFoundException(Exception): class CodeNotFoundException(Exception):
pass pass
@ -25,6 +27,18 @@ class UpdateError(graphene.ObjectType):
errors = graphene.List(FieldError) errors = graphene.List(FieldError)
class TeacherOnlyMutation(relay.ClientIDMutation):
class Meta:
abstract = True
@classmethod
def mutate(cls, root, info, input):
user = info.context.user
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
raise PermissionError('Permission denied')
return super().mutate(root, info, input)
class UpdatePassword(relay.ClientIDMutation): class UpdatePassword(relay.ClientIDMutation):
class Input: class Input:
password_input = graphene.Argument(PasswordUpdateInput) password_input = graphene.Argument(PasswordUpdateInput)
@ -154,7 +168,7 @@ class AddRemoveMember(relay.ClientIDMutation):
school_class = get_object(SchoolClass, school_class_id) school_class = get_object(SchoolClass, school_class_id)
if not user.is_teacher() or not school_class.users.filter(pk=user.pk).exists(): if not user.is_teacher() or not school_class.users.filter(pk=user.pk).exists():
raise PermissionError('Fehlende Berechtigung') raise PermissionError('Permission denied')
school_class_member = SchoolClassMember.objects.get(user__pk=member_pk, school_class=school_class) school_class_member = SchoolClassMember.objects.get(user__pk=member_pk, school_class=school_class)
school_class_member.active = active school_class_member.active = active
@ -163,7 +177,7 @@ class AddRemoveMember(relay.ClientIDMutation):
return cls(success=True) return cls(success=True)
class UpdateSchoolClass(relay.ClientIDMutation): class UpdateSchoolClass(TeacherOnlyMutation):
class Input: class Input:
id = graphene.ID(required=True) id = graphene.ID(required=True)
name = graphene.String() name = graphene.String()
@ -177,9 +191,7 @@ class UpdateSchoolClass(relay.ClientIDMutation):
name = kwargs.get('name') name = kwargs.get('name')
user = info.context.user user = info.context.user
if 'users.can_manage_school_class_content' not in user.get_role_permissions(): # todo: only allow to edit your own school class
raise PermissionError()
school_class = get_object(SchoolClass, id) school_class = get_object(SchoolClass, id)
school_class.name = name school_class.name = name
school_class.save() school_class.save()
@ -187,7 +199,7 @@ class UpdateSchoolClass(relay.ClientIDMutation):
return cls(success=True, school_class=school_class) return cls(success=True, school_class=school_class)
class CreateSchoolClass(relay.ClientIDMutation): class CreateSchoolClass(TeacherOnlyMutation):
class Input: class Input:
name = graphene.String() name = graphene.String()
@ -197,30 +209,14 @@ class CreateSchoolClass(relay.ClientIDMutation):
@classmethod @classmethod
def mutate_and_get_payload(cls, root, info, **kwargs): def mutate_and_get_payload(cls, root, info, **kwargs):
name = kwargs.get('name') name = kwargs.get('name')
user = info.context.user user = info.context.user
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
raise PermissionError()
school_class = SchoolClass.objects.create(name=name) school_class = SchoolClass.objects.create(name=name)
SchoolClassMember.objects.create(school_class=school_class, user=user) SchoolClassMember.objects.create(school_class=school_class, user=user)
user.set_selected_class(school_class) user.set_selected_class(school_class)
return cls(success=True, school_class=school_class) return cls(success=True, school_class=school_class)
class TeacherOnlyMutation(relay.ClientIDMutation):
class Meta:
abstract = True
@classmethod
def mutate(cls, root, info, input):
user = info.context.user
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
raise PermissionError('Missing permissions')
return super().mutate(root, info, input)
class CreateTeam(TeacherOnlyMutation): class CreateTeam(TeacherOnlyMutation):
class Input: class Input:
name = graphene.String(required=True) name = graphene.String(required=True)
@ -240,6 +236,30 @@ class CreateTeam(TeacherOnlyMutation):
return cls(success=True, team=team) return cls(success=True, team=team)
class UpdateTeam(TeacherOnlyMutation):
class Input:
id = graphene.ID(required=True)
name = graphene.String()
success = graphene.Boolean()
team = graphene.Field(TeamNode)
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
id = kwargs.get('id')
name = kwargs.get('name')
user = info.context.user
team = get_object(Team, id)
if user not in team.members.all():
logger.info('User not part of this team')
raise PermissionError('Permission denied')
team.name = name
team.save()
return cls(success=True, team=team)
class JoinTeam(TeacherOnlyMutation): class JoinTeam(TeacherOnlyMutation):
class Input: class Input:
code = graphene.String(required=True) code = graphene.String(required=True)
@ -285,3 +305,4 @@ class ProfileMutations:
update_onboarding_progress = UpdateOnboardingProgress.Field() update_onboarding_progress = UpdateOnboardingProgress.Field()
create_team = CreateTeam.Field() create_team = CreateTeam.Field()
join_team = JoinTeam.Field() join_team = JoinTeam.Field()
update_team = UpdateTeam.Field()

View File

@ -1,32 +1,16 @@
# -*- coding: utf-8 -*-
#
# ITerativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2019 ITerativ GmbH. All rights reserved.
#
# Created on 2019-10-10
# @author: chrigu <christian.cueni@iterativ.ch>
from django.conf import settings
# -*- coding: utf-8 -*-
#
# ITerativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2019 ITerativ GmbH. All rights reserved.
#
# Created on 2019-04-09
# @author: chrigu <christian.cueni@iterativ.ch>
from django.test import TestCase, RequestFactory from django.test import TestCase, RequestFactory
from graphene import Context
from graphene.test import Client from graphene.test import Client
from graphql_relay import to_global_id from graphql_relay import to_global_id
from api.utils import get_graphql_mutation, get_object
from core.factories import UserFactory
from users.models import SchoolClass, User
from api.schema import schema from api.schema import schema
from api.utils import get_graphql_mutation, get_object
from core.factories import UserFactory, TeacherFactory
from users.models import SchoolClass, User
from users.services import create_users from users.services import create_users
UPDATE_SCHOOL_CLASS_MUTATION = get_graphql_mutation('updateSchoolClass.gql')
class SchoolClassesTest(TestCase): class SchoolClassesTest(TestCase):
@ -53,6 +37,7 @@ class SchoolClassesTest(TestCase):
class_name = SchoolClass.generate_default_group_name(user=user) class_name = SchoolClass.generate_default_group_name(user=user)
self.assertEqual(f'{self.prefix} {user.pk}', class_name) self.assertEqual(f'{self.prefix} {user.pk}', class_name)
class ModifySchoolClassTest(TestCase): class ModifySchoolClassTest(TestCase):
def setUp(self): def setUp(self):
create_users() create_users()
@ -72,9 +57,8 @@ class ModifySchoolClassTest(TestCase):
school_class = SchoolClass.objects.get(name='skillbox') school_class = SchoolClass.objects.get(name='skillbox')
self.assertEqual(school_class.name, 'skillbox') self.assertEqual(school_class.name, 'skillbox')
id = to_global_id('SchoolClassNode', school_class.id) id = to_global_id('SchoolClassNode', school_class.id)
mutation = get_graphql_mutation('updateSchoolClass.gql')
result = self.client.execute(mutation, variables={ result = self.client.execute(UPDATE_SCHOOL_CLASS_MUTATION, variables={
'input': { 'input': {
'id': id, 'id': id,
'name': class_name 'name': class_name
@ -85,15 +69,30 @@ 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)
def test_update_school_class_not_in_class_fails(self):
client = Client(schema=schema)
teacher = TeacherFactory(username='conan')
context = Context(user=teacher)
school_class = SchoolClass.objects.get(name='skillbox')
self.assertEqual(school_class.name, 'skillbox')
id = to_global_id('SchoolClassNode', school_class.id)
variables = {
'input': {
'id': id,
'name': 'Nein'
}
}
result = client.execute(UPDATE_SCHOOL_CLASS_MUTATION, variables=variables, context=context)
self.assertIsNone(result.get('errors'))
def test_update_school_class_fail(self): def test_update_school_class_fail(self):
class_name = 'Nanana' class_name = 'Nanana'
school_class = SchoolClass.objects.get(name='skillbox') school_class = SchoolClass.objects.get(name='skillbox')
self.assertEqual(school_class.name, 'skillbox') self.assertEqual(school_class.name, 'skillbox')
id = to_global_id('SchoolClassNode', school_class.id) id = to_global_id('SchoolClassNode', school_class.id)
mutation = get_graphql_mutation('updateSchoolClass.gql')
result = self.student_client.execute(mutation, variables={ result = self.student_client.execute(UPDATE_SCHOOL_CLASS_MUTATION, variables={
'input': { 'input': {
'id': id, 'id': id,
'name': class_name 'name': class_name

View File

@ -1,6 +1,7 @@
from django.test import TestCase from django.test import TestCase
from graphene import Context from graphene import Context
from graphene.test import Client from graphene.test import Client
from graphql_relay import to_global_id
from api.schema import schema from api.schema import schema
from api.utils import get_graphql_mutation from api.utils import get_graphql_mutation
@ -21,6 +22,7 @@ ME_QUERY = """
CREATE_TEAM_MUTATION = get_graphql_mutation('createTeam.gql') CREATE_TEAM_MUTATION = get_graphql_mutation('createTeam.gql')
JOIN_TEAM_MUTATION = get_graphql_mutation('joinTeam.gql') JOIN_TEAM_MUTATION = get_graphql_mutation('joinTeam.gql')
UPDATE_TEAM_MUTATION = get_graphql_mutation('updateTeam.gql')
class TeamTest(TestCase): class TeamTest(TestCase):
@ -29,6 +31,7 @@ class TeamTest(TestCase):
self.team_name = 'Fiterativ' self.team_name = 'Fiterativ'
self.code = 'AAAA' self.code = 'AAAA'
self.team = TeamFactory(name=self.team_name, code=self.code) self.team = TeamFactory(name=self.team_name, code=self.code)
self.team_id = to_global_id('TeamNode', self.team.id)
self.user = TeacherFactory(username='ueli', team=self.team) self.user = TeacherFactory(username='ueli', team=self.team)
self.student = UserFactory(username='fritzli') self.student = UserFactory(username='fritzli')
self.context = Context(user=self.user) self.context = Context(user=self.user)
@ -43,7 +46,7 @@ class TeamTest(TestCase):
def permission_error(self, result): def permission_error(self, result):
errors = result.get('errors') errors = result.get('errors')
self.assertIsNotNone(errors) self.assertIsNotNone(errors)
self.assertIn('permission', errors[0]['message']) self.assertIn('Permission denied', errors[0]['message'])
def check_me(self, context, name, code): def check_me(self, context, name, code):
result = self.client.execute(ME_QUERY, context=context) result = self.client.execute(ME_QUERY, context=context)
@ -99,6 +102,50 @@ class TeamTest(TestCase):
self.assertEqual(team.get('name'), team_name) self.assertEqual(team.get('name'), team_name)
self.assertIsNotNone(team.get('code')) self.assertIsNotNone(team.get('code'))
def test_update_team_name(self):
new_name = 'Team Böhmermann'
variables = {
"input": {
"name": new_name,
"id": self.team_id
}
}
result = self.client.execute(UPDATE_TEAM_MUTATION, context=self.context, variables=variables)
self.no_error(result)
update_team = result.get('data').get('updateTeam')
team = update_team.get('team')
success = update_team.get('success')
self.assertTrue(success)
self.assertEqual(team.get('name'), new_name)
def test_update_team_name_as_student_fails(self):
context = Context(user=self.student)
variables = {
"input": {
"name": 'Not gonna happen',
"id": self.team_id
}
}
result = self.client.execute(UPDATE_TEAM_MUTATION, context=context, variables=variables)
self.permission_error(result)
def test_update_team_name_not_in_team_fails(self):
schelm = TeacherFactory(username='schelm')
context = Context(user=schelm)
team = Team.objects.get(pk=self.team.pk)
old_name = team.name
self.assertFalse(self.team.members.filter(pk=schelm.pk).exists())
variables = {
"input": {
"name": 'Not gonna happen',
"id": self.team_id
}
}
result = self.client.execute(UPDATE_TEAM_MUTATION, context=context, variables=variables)
self.permission_error(result)
team = Team.objects.get(pk=self.team.pk)
self.assertEqual(team.name, old_name)
def test_create_team_mutation_as_student_fails(self): def test_create_team_mutation_as_student_fails(self):
self.assertEqual(Team.objects.count(), 1) self.assertEqual(Team.objects.count(), 1)
variables = { variables = {