Restrict deletion of rooms to teachers
This commit is contained in:
parent
58d42e2472
commit
62bd0b2435
|
|
@ -5,7 +5,7 @@
|
||||||
<room-group-widget v-bind="schoolClass"></room-group-widget>
|
<room-group-widget v-bind="schoolClass"></room-group-widget>
|
||||||
<room-entry-count-widget :entryCount="entryCount"></room-entry-count-widget>
|
<room-entry-count-widget :entryCount="entryCount"></room-entry-count-widget>
|
||||||
</router-link>
|
</router-link>
|
||||||
<div class="room-widget__footer">
|
<div class="room-widget__footer" v-if="canEditRoom">
|
||||||
<div>
|
<div>
|
||||||
<a @click="showMenu = !showMenu" class="room-widget__more-link">
|
<a @click="showMenu = !showMenu" class="room-widget__more-link">
|
||||||
<ellipses></ellipses>
|
<ellipses></ellipses>
|
||||||
|
|
@ -30,6 +30,8 @@
|
||||||
import RoomEntryCountWidget from '@/components/rooms/RoomEntryCountWidget';
|
import RoomEntryCountWidget from '@/components/rooms/RoomEntryCountWidget';
|
||||||
import WidgetPopover from '@/components/rooms/WidgetPopover';
|
import WidgetPopover from '@/components/rooms/WidgetPopover';
|
||||||
|
|
||||||
|
import {meQuery} from '@/graphql/queries';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['slug', 'title', 'entryCount', 'appearance', 'schoolClass', 'id'],
|
props: ['slug', 'title', 'entryCount', 'appearance', 'schoolClass', 'id'],
|
||||||
|
|
||||||
|
|
@ -42,16 +44,26 @@
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showMenu: false
|
showMenu: false,
|
||||||
|
me: {
|
||||||
|
permissions: []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
roomClass() {
|
roomClass() {
|
||||||
return `room-widget--${this.appearance}`
|
return `room-widget--${this.appearance}`
|
||||||
|
},
|
||||||
|
canEditRoom() {
|
||||||
|
return this.me.permissions.includes('users.can_manage_school_class_content');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
me: meQuery
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
deleteRoom(id) {
|
deleteRoom(id) {
|
||||||
this.$apollo.mutate({
|
this.$apollo.mutate({
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import graphene
|
import graphene
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
from graphql_relay import to_global_id, from_global_id
|
from graphql_relay import to_global_id, from_global_id
|
||||||
|
|
||||||
|
|
@ -64,9 +65,14 @@ class DeleteRoom(relay.ClientIDMutation):
|
||||||
errors = graphene.List(graphene.String)
|
errors = graphene.List(graphene.String)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def mutate_and_get_payload(cls, *args, **kwargs):
|
def mutate_and_get_payload(cls, root, info, **kwargs):
|
||||||
id = kwargs.get('id')
|
id = kwargs.get('id')
|
||||||
room = get_object(Room, id)
|
room = get_object(Room, id)
|
||||||
|
user = info.context.user
|
||||||
|
if not user.has_perm('users.can_manage_school_class_content'):
|
||||||
|
raise PermissionDenied('Missing permissions')
|
||||||
|
if room.school_class not in user.school_classes.all():
|
||||||
|
raise PermissionDenied('Permission denied: Incorrect school classes')
|
||||||
room.delete()
|
room.delete()
|
||||||
return cls(success=True)
|
return cls(success=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
from django.test import TestCase, RequestFactory
|
||||||
|
from graphene.test import Client
|
||||||
|
from graphql_relay import to_global_id
|
||||||
|
|
||||||
|
from api.schema import schema
|
||||||
|
from rooms.factories import RoomFactory
|
||||||
|
from rooms.models import Room
|
||||||
|
from users.models import User, SchoolClass
|
||||||
|
from users.services import create_users
|
||||||
|
|
||||||
|
|
||||||
|
class RoomDeleteEditPermissionsTestcase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
create_users()
|
||||||
|
self.teacher = User.objects.get(username='teacher')
|
||||||
|
self.teacher2 = User.objects.get(username='teacher2')
|
||||||
|
self.student = User.objects.get(username='student1')
|
||||||
|
school_class = SchoolClass.objects.get(name='skillbox')
|
||||||
|
self.room = RoomFactory(school_class=school_class)
|
||||||
|
self.mutation = '''
|
||||||
|
mutation DeleteRoom($input: DeleteRoomInput!) {
|
||||||
|
deleteRoom(input: $input) {
|
||||||
|
success
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
self.variables = {
|
||||||
|
'input': {
|
||||||
|
'id': to_global_id('RoomNode', self.room.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_delete_own_room(self):
|
||||||
|
self.assertEqual(Room.objects.count(), 1)
|
||||||
|
request = RequestFactory().get('/')
|
||||||
|
request.user = self.teacher
|
||||||
|
self.client = Client(schema=schema, context_value=request)
|
||||||
|
|
||||||
|
|
||||||
|
result = self.client.execute(self.mutation, variables=self.variables)
|
||||||
|
|
||||||
|
self.assertIsNone(result.get('errors'))
|
||||||
|
self.assertEqual(Room.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_delete_room_as_student(self):
|
||||||
|
self.assertEqual(Room.objects.count(), 1)
|
||||||
|
request = RequestFactory().get('/')
|
||||||
|
request.user = self.student
|
||||||
|
self.client = Client(schema=schema, context_value=request)
|
||||||
|
|
||||||
|
result = self.client.execute(self.mutation, variables=self.variables)
|
||||||
|
|
||||||
|
self.assertIsNotNone(result.get('errors'))
|
||||||
|
self.assertEqual(Room.objects.count(), 1)
|
||||||
|
|
||||||
|
def test_delete_room_of_other_class(self):
|
||||||
|
self.assertEqual(Room.objects.count(), 1)
|
||||||
|
request = RequestFactory().get('/')
|
||||||
|
request.user = self.teacher2
|
||||||
|
self.client = Client(schema=schema, context_value=request)
|
||||||
|
|
||||||
|
result = self.client.execute(self.mutation, variables=self.variables)
|
||||||
|
|
||||||
|
self.assertIsNotNone(result.get('errors'))
|
||||||
|
self.assertEqual(Room.objects.count(), 1)
|
||||||
Loading…
Reference in New Issue