Add mutation to remove member from class
This commit is contained in:
parent
a99a073460
commit
b82b82369c
|
|
@ -0,0 +1,5 @@
|
||||||
|
mutation RemoveMember($input: RemoveMemberInput!) {
|
||||||
|
removeMember(input: $input) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
Loading…
Reference in New Issue