restrict access to users and rooms, add tests

This commit is contained in:
Christian Cueni 2019-03-14 12:12:31 +01:00
parent 319725ae57
commit ba1e63a84b
5 changed files with 152 additions and 6 deletions

View File

@ -1,10 +1,10 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db import models from django.db import models
from django_extensions.db.models import TitleDescriptionModel, TitleSlugDescriptionModel from django_extensions.db.models import TitleSlugDescriptionModel
from wagtail.core.fields import StreamField from wagtail.core.fields import StreamField
from books.blocks import ImageUrlBlock, LinkBlock, VideoBlock from books.blocks import ImageUrlBlock, LinkBlock, VideoBlock
from books.models import ContentBlock, TextBlock from books.models import TextBlock
from users.models import SchoolClass from users.models import SchoolClass
@ -37,3 +37,6 @@ class RoomEntry(TitleSlugDescriptionModel):
def __str__(self): def __str__(self):
return 'RoomEntry {}-{}-{}'.format(self.id, self.title, self.author) return 'RoomEntry {}-{}-{}'.format(self.id, self.title, self.author)
def can_user_see_entry(self, user):
return user.is_superuser or self.room.school_class.is_user_in_schoolclass(user)

View File

@ -55,14 +55,29 @@ class RoomsQuery(object):
return Room.objects.filter(school_class__in=user.school_classes.all()) return Room.objects.filter(school_class__in=user.school_classes.all())
def resolve_room(self, info, **kwargs): def resolve_room(self, info, **kwargs):
return get_by_id_or_slug(Room, **kwargs) room = get_by_id_or_slug(Room, **kwargs)
if room.school_class.is_user_in_schoolclass(info.context.user):
return room
else:
return None
def resolve_room_entry(self, info, **kwargs): def resolve_room_entry(self, info, **kwargs):
slug = kwargs.get('slug') slug = kwargs.get('slug')
id = kwargs.get('id') id = kwargs.get('id')
room_entry = None
if id is not None: if id is not None:
return get_object(RoomEntry, id) room_entry = get_object(RoomEntry, id)
if slug is not None: if slug is not None:
return RoomEntry.objects.get(slug=slug) room_entry = RoomEntry.objects.get(slug=slug)
return None
if room_entry and room_entry.can_user_see_entry(info.context.user):
return room_entry
else:
return None
def resolve_all_room_entries(self, info, **kwargs):
if not info.context.user.is_superuser:
return RoomEntry.objects.none()
else:
return RoomEntry.objects.all()

View File

@ -0,0 +1,119 @@
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 rooms.factories import RoomFactory, RoomEntryFactory
from rooms.models import Room
from users.factories import SchoolClassFactory
class RoomQueryPermission(TestCase):
@staticmethod
def get_first_contents(result):
return result.get('data').get('rooms').get('edges')[0]
def setUp(self):
self.user = UserFactory(username='aschi')
self.another_user = UserFactory(username='pesche')
sc1 = SchoolClassFactory(users=[self.user])
sc2 = SchoolClassFactory(users=[self.another_user])
self.room1 = RoomFactory(school_class=sc1)
self.room2 = RoomFactory(school_class=sc2)
request = RequestFactory().get('/')
request.user = self.user
self.client = Client(schema=schema, context_value=request)
def test_student_should_only_see_rooms_of_class(self):
query = '''
query {
rooms {
edges {
node {
title
}
}
}
}
'''
result = self.client.execute(query)
self.assertIsNone(result.get('errors'))
self.assertEqual(len(result.get('data').get('rooms').get('edges')), 1)
self.assertEqual(result.get('data').get('rooms').get('edges')[0].get('node').get('title'), self.room1.title)
def test_student_should_not_be_able_to_query_rooms_of_other_classes(self):
query = '''
query RoomQuery($slug: String) {
room(slug: $slug) {
title
}
}
'''
result = self.client.execute(query, variables={
'slug': self.room2.slug
})
self.assertIsNone(result.get('errors'))
self.assertEqual(result.get('data').get('room'), None)
class RoomEntryQueryPermissions(TestCase):
@staticmethod
def get_first_contents(result):
return result.get('data').get('rooms').get('edges')[0]
def setUp(self):
self.user = UserFactory(username='aschi')
self.another_user = UserFactory(username='pesche')
sc1 = SchoolClassFactory(users=[self.user])
sc2 = SchoolClassFactory(users=[self.another_user])
room1 = RoomFactory(school_class=sc1)
room2 = RoomFactory(school_class=sc2)
self.roomEntry1 = RoomEntryFactory(room=room1, author=self.user)
self.roomEntry2 = RoomEntryFactory(room=room2, author=self.another_user)
request = RequestFactory().get('/')
request.user = self.user
self.client = Client(schema=schema, context_value=request)
def test_user_should_see_room_entries_from_own_class(self):
query = '''
query RoomEntryQuery($slug: String) {
roomEntry(slug: $slug) {
title
}
}
'''
result = self.client.execute(query, variables={
'slug': self.roomEntry1.slug
})
self.assertIsNone(result.get('errors'))
self.assertEqual(result.get('data').get('roomEntry').get('title'), self.roomEntry1.title)
def test_user_should_not_see_room_entries_from_orther_class(self):
query = '''
query RoomEntryQuery($slug: String) {
roomEntry(slug: $slug) {
title
}
}
'''
result = self.client.execute(query, variables={
'slug': self.roomEntry2.slug
})
self.assertIsNone(result.get('errors'))
self.assertEqual(result.get('data').get('roomEntry'), None)

View File

@ -51,6 +51,9 @@ class SchoolClass(models.Model):
def __str__(self): def __str__(self):
return 'SchoolClass {}-{}-{}'.format(self.id, self.name, self.year) return 'SchoolClass {}-{}-{}'.format(self.id, self.name, self.year)
def is_user_in_schoolclass(self, user):
return user.is_superuser or user.school_classes.filter(pk=self.id).count() > 0
class Role(models.Model): class Role(models.Model):
key = models.CharField(_('Key'), max_length=100, blank=False, null=False, unique=True) key = models.CharField(_('Key'), max_length=100, blank=False, null=False, unique=True)

View File

@ -45,3 +45,9 @@ class UsersQuery(object):
def resolve_me(self, info, **kwargs): def resolve_me(self, info, **kwargs):
return info.context.user return info.context.user
def resolve_all_users(self, info, **kwargs):
if not info.context.user.is_superuser:
return User.objects.none()
else:
return User.objects.all()