Add mutation to remove member from class

This commit is contained in:
Ramon Wenger 2020-03-05 15:14:26 +01:00
parent a99a073460
commit b82b82369c
5 changed files with 158 additions and 8 deletions

View File

@ -0,0 +1,5 @@
mutation RemoveMember($input: RemoveMemberInput!) {
removeMember(input: $input) {
success
}
}

View File

@ -7,15 +7,24 @@ from .models import User, SchoolClass, Role, UserRole, UserSetting
class SchoolClassInline(admin.TabularInline): class SchoolClassInline(admin.TabularInline):
model = SchoolClass.users.through model = SchoolClass.users.through
extra = 1
class RoleInline(admin.TabularInline): class RoleInline(admin.TabularInline):
model = UserRole model = UserRole
extra = 1
@admin.register(SchoolClass) @admin.register(SchoolClass)
class SchoolClassAdmin(admin.ModelAdmin): class SchoolClassAdmin(admin.ModelAdmin):
list_display = ('name', 'code', 'is_deleted') list_display = ('name', 'code', 'user_list', 'is_deleted')
inlines = [
SchoolClassInline
]
def user_list(self, obj):
return ', '.join([s.username for s in obj.users.all()])
@admin.register(Role) @admin.register(Role)

View File

@ -2,7 +2,7 @@ import random
import factory import factory
from users.models import SchoolClass from users.models import SchoolClass, SchoolClassMember
class_types = ['DA', 'KV', 'INF', 'EE'] class_types = ['DA', 'KV', 'INF', 'EE']
class_suffix = ['A', 'B', 'C', 'D', 'E'] class_suffix = ['A', 'B', 'C', 'D', 'E']
@ -16,7 +16,8 @@ class SchoolClassFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = SchoolClass model = SchoolClass
name = factory.Sequence(lambda n: '{}{}{}'.format(random.choice(class_types), '18', class_suffix[n % len(class_suffix)])) name = factory.Sequence(
lambda n: '{}{}{}'.format(random.choice(class_types), '18', class_suffix[n % len(class_suffix)]))
is_deleted = False is_deleted = False
@factory.post_generation @factory.post_generation
@ -28,4 +29,4 @@ class SchoolClassFactory(factory.django.DjangoModelFactory):
if extracted: if extracted:
# A list of groups were passed in, use them # A list of groups were passed in, use them
for user in extracted: for user in extracted:
self.users.add(user) SchoolClassMember.objects.create(user=user, school_class=self, active=True)

View File

@ -3,10 +3,11 @@ from django.contrib.auth import update_session_auth_hash
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models import Q from django.db.models import Q
from graphene import relay from graphene import relay
from graphql_relay import from_global_id
from api.utils import get_object from api.utils import get_object
from users.inputs import PasswordUpdateInput from users.inputs import PasswordUpdateInput
from users.models import SchoolClass, UserSetting from users.models import SchoolClass, UserSetting, User, SchoolClassMember
from users.schema import SchoolClassNode from users.schema import SchoolClassNode
from users.serializers import PasswordSerialzer, AvatarUrlSerializer from users.serializers import PasswordSerialzer, AvatarUrlSerializer
@ -122,15 +123,40 @@ class JoinClass(relay.ClientIDMutation):
try: try:
school_class = SchoolClass.objects.get(Q(code__iexact=code)) school_class = SchoolClass.objects.get(Q(code__iexact=code))
if user not in list(school_class.users.all()): if user not in list(school_class.users.all()):
school_class.users.add(user) school_class.users.add(user)
else: else:
raise CodeNotFoundException('[CAJ] Schüler ist bereits in Klasse') # CAJ = Class Already Joined raise CodeNotFoundException('[CAJ] Schüler ist bereits in Klasse') # CAJ = Class Already Joined
return cls(success=True, school_class=school_class) return cls(success=True, school_class=school_class)
except SchoolClass.DoesNotExist: except SchoolClass.DoesNotExist:
raise CodeNotFoundException('[CNV] Code ist nicht gültig') # CAV = Code Not Valid raise CodeNotFoundException('[CNV] Code ist nicht gültig') # CAV = Code Not Valid
class RemoveMember(relay.ClientIDMutation):
class Input:
member = graphene.ID(required=True)
school_class = graphene.ID(required=True)
success = graphene.Boolean()
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
member_id = kwargs.get('member')
school_class_id = kwargs.get('school_class')
user = info.context.user
member_pk = from_global_id(member_id)[1]
school_class = get_object(SchoolClass, school_class_id)
if not user.is_teacher() or not school_class.users.filter(pk=user.pk).exists():
raise PermissionError('Fehlende Berechtigung')
school_class_member = SchoolClassMember.objects.get(user__pk=member_pk, school_class=school_class)
school_class_member.active = False
school_class_member.save()
return cls(success=True)
class ProfileMutations: class ProfileMutations:
@ -138,3 +164,4 @@ class ProfileMutations:
update_avatar = UpdateAvatar.Field() update_avatar = UpdateAvatar.Field()
update_setting = UpdateSetting.Field() update_setting = UpdateSetting.Field()
join_class = JoinClass.Field() join_class = JoinClass.Field()
remove_member = RemoveMember.Field()

View File

@ -0,0 +1,108 @@
from django.test import TestCase
from graphene import Context
from graphene.test import Client
from graphql_relay import to_global_id
from api.utils import get_graphql_mutation
from core.factories import UserFactory
from users.factories import SchoolClassFactory
from users.models import SchoolClass, User, SchoolClassMember
from api.schema import schema
from users.services import create_users
class JoinSchoolClassTest(TestCase):
def setUp(self):
self.client = Client(schema=schema)
self.school_class_name = 'Moordale'
user_data = [
{
'teacher': ('Emily', 'Sands',),
'class': self.school_class_name,
'code': 'SEXED',
'students': [
('Otis', 'Milburn'),
('Maeve', 'Wiley'),
('Adam', 'Groff'),
('Eric', 'Effiong'),
('Jackson', 'Marchetti'),
]
},
{
'teacher': ('Colin', 'Hendricks'),
'class': 'Swing Band',
'students': [
('Ola', 'Nyman'),
]
}
]
create_users(user_data)
teacher = User.objects.get(username='emily.sands')
self.teacher_id = to_global_id('UserNode', teacher.pk)
student = User.objects.get(username='adam.groff')
self.student_id = to_global_id('UserNode', student.pk)
other_student = User.objects.get(username='eric.effiong')
self.other_student_id = to_global_id('UserNode', other_student.pk)
school_class = SchoolClass.objects.get(name=self.school_class_name)
self.school_class_id = to_global_id('SchoolClassNode', school_class.pk)
self.teacher_context = Context(user=teacher)
self.student_context = Context(user=student)
self.mutation = get_graphql_mutation('removeMember.gql')
def test_leave_class(self):
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=True).count(), 6)
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=False).count(),
0)
result = self.client.execute(self.mutation, variables={
'input': {
'schoolClass': self.school_class_id,
'member': self.student_id
}
}, context=self.teacher_context)
self.assertIsNone(result.get('errors'))
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=True).count(), 5)
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=False).count(),
1)
def test_leave_class_student_raises_error(self):
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=True).count(), 6)
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=False).count(), 0)
result = self.client.execute(self.mutation, variables={
'input': {
'schoolClass': self.school_class_id,
'member': self.other_student_id
}
}, context=self.student_context)
self.assertIsNotNone(result['errors'])
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=True).count(), 6)
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=False).count(), 0)
def test_leave_class_other_school_class_raises_error(self):
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=True).count(), 6)
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=False).count(), 0)
student = User.objects.get(username='ola.nyman')
school_class = SchoolClass.objects.get(name='Swing Band')
result = self.client.execute(self.mutation, variables={
'input': {
'schoolClass': to_global_id('SchoolClassNode', school_class.id),
'member': to_global_id('UserNode', student.id)
}
}, context=self.teacher_context)
self.assertIsNotNone(result['errors'])
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=True).count(), 6)
self.assertEqual(
SchoolClassMember.objects.filter(school_class__name=self.school_class_name, active=False).count(), 0)