Add share snapshot mutation, including unit tests
This commit is contained in:
parent
631bfb338a
commit
4bdcdd8774
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.22 on 2021-05-08 20:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('books', '0027_auto_20210429_1444'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='snapshot',
|
||||||
|
name='shared',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -71,6 +71,7 @@ class Snapshot(models.Model):
|
||||||
)
|
)
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
creator = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True)
|
creator = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True)
|
||||||
|
shared = models.BooleanField(default=False)
|
||||||
|
|
||||||
objects = SnapshotManager()
|
objects = SnapshotManager()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from books.schema.mutations.chapter import UpdateChapterVisibility
|
from books.schema.mutations.chapter import UpdateChapterVisibility
|
||||||
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
|
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
|
||||||
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, SyncModuleVisibility
|
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, SyncModuleVisibility
|
||||||
from books.schema.mutations.snapshot import CreateSnapshot, ApplySnapshot
|
from books.schema.mutations.snapshot import CreateSnapshot, ApplySnapshot, ShareSnapshot
|
||||||
from books.schema.mutations.topic import UpdateLastTopic
|
from books.schema.mutations.topic import UpdateLastTopic
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -16,3 +16,4 @@ class BookMutations(object):
|
||||||
sync_module_visibility = SyncModuleVisibility.Field()
|
sync_module_visibility = SyncModuleVisibility.Field()
|
||||||
create_snapshot = CreateSnapshot.Field()
|
create_snapshot = CreateSnapshot.Field()
|
||||||
apply_snapshot = ApplySnapshot.Field()
|
apply_snapshot = ApplySnapshot.Field()
|
||||||
|
share_snapshot = ShareSnapshot.Field()
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class ApplySnapshot(relay.ClientIDMutation):
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
selected_class_id = args.get('selected_class')
|
selected_class_id = args.get('selected_class')
|
||||||
selected_class = get_object(SchoolClass, selected_class_id)
|
selected_class = get_object(SchoolClass, selected_class_id)
|
||||||
#reset everything
|
# reset everything
|
||||||
for chapter in Chapter.get_by_parent(snapshot.module):
|
for chapter in Chapter.get_by_parent(snapshot.module):
|
||||||
cb_qs = ContentBlock.get_by_parent(chapter)
|
cb_qs = ContentBlock.get_by_parent(chapter)
|
||||||
without_owner = Q(owner__isnull=True)
|
without_owner = Q(owner__isnull=True)
|
||||||
|
|
@ -55,7 +55,7 @@ class ApplySnapshot(relay.ClientIDMutation):
|
||||||
cb.hidden_for.remove(selected_class)
|
cb.hidden_for.remove(selected_class)
|
||||||
for cb in cb_qs.filter(owner_user):
|
for cb in cb_qs.filter(owner_user):
|
||||||
cb.visible_for.remove(selected_class)
|
cb.visible_for.remove(selected_class)
|
||||||
#apply snapshot
|
# apply snapshot
|
||||||
if not selected_class.users.filter(username=user.username).exists() or not user.is_teacher():
|
if not selected_class.users.filter(username=user.username).exists() or not user.is_teacher():
|
||||||
raise PermissionError('Not allowed')
|
raise PermissionError('Not allowed')
|
||||||
for content_block in snapshot.hidden_content_blocks.all():
|
for content_block in snapshot.hidden_content_blocks.all():
|
||||||
|
|
@ -69,3 +69,24 @@ class ApplySnapshot(relay.ClientIDMutation):
|
||||||
if chapter_snapshot.description_hidden:
|
if chapter_snapshot.description_hidden:
|
||||||
chapter.description_hidden_for.add(selected_class)
|
chapter.description_hidden_for.add(selected_class)
|
||||||
return cls(success=True, module=snapshot.module)
|
return cls(success=True, module=snapshot.module)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshot(relay.ClientIDMutation):
|
||||||
|
class Input:
|
||||||
|
snapshot = graphene.ID(required=True)
|
||||||
|
shared = graphene.Boolean(required=True)
|
||||||
|
|
||||||
|
success = graphene.Boolean(required=True)
|
||||||
|
snapshot = graphene.Field(SnapshotNode)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate_and_get_payload(cls, root, info, **args):
|
||||||
|
snapshot_id = args.get('snapshot')
|
||||||
|
shared = args.get('shared')
|
||||||
|
user = info.context.user
|
||||||
|
snapshot = get_object(Snapshot, snapshot_id)
|
||||||
|
if snapshot.creator != user:
|
||||||
|
raise PermissionError('Not permitted')
|
||||||
|
snapshot.shared = shared
|
||||||
|
snapshot.save()
|
||||||
|
return cls(success=True, snapshot=snapshot)
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ class ModuleNode(DjangoObjectType):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_snapshots(parent, info, **kwargs):
|
def resolve_snapshots(parent, info, **kwargs):
|
||||||
return parent.snapshots.all()
|
return parent.snapshots.filter(creator=info.context.user)
|
||||||
|
|
||||||
|
|
||||||
class RecentModuleNode(DjangoObjectType):
|
class RecentModuleNode(DjangoObjectType):
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,32 @@ query SnapshotDetail($id: ID!) {
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
SHARE_SNAPSHOT_MUTATION = """
|
||||||
|
mutation ShareSnapshot($input: ShareSnapshotInput!) {
|
||||||
|
shareSnapshot(input: $input) {
|
||||||
|
success
|
||||||
|
snapshot {
|
||||||
|
shared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
MODULE_SNAPSHOTS_QUERY = """
|
||||||
|
query SnapshotQuery($slug: String!) {
|
||||||
|
module(slug: $slug) {
|
||||||
|
snapshots {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
created
|
||||||
|
creator {
|
||||||
|
username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def edges_to_array(entity):
|
def edges_to_array(entity):
|
||||||
return [edge['node'] for edge in entity.get('edges')]
|
return [edge['node'] for edge in entity.get('edges')]
|
||||||
|
|
@ -263,3 +289,53 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb1['hiddenFor']])
|
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb1['hiddenFor']])
|
||||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb2['hiddenFor']])
|
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb2['hiddenFor']])
|
||||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb3['visibleFor']])
|
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb3['visibleFor']])
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotTestCase(SkillboxTestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.createDefault()
|
||||||
|
self.client = self.get_client()
|
||||||
|
self.slug = 'some-module'
|
||||||
|
|
||||||
|
self.teacher2 = User.objects.get(username='teacher2')
|
||||||
|
self.module = ModuleFactory(slug=self.slug)
|
||||||
|
self.skillbox_class = SchoolClass.objects.get(name='skillbox')
|
||||||
|
self.snapshot = Snapshot.objects.create_snapshot(module=self.module, school_class=self.skillbox_class,
|
||||||
|
user=self.teacher)
|
||||||
|
Snapshot.objects.create_snapshot(module=self.module, school_class=self.skillbox_class,
|
||||||
|
user=self.teacher2)
|
||||||
|
|
||||||
|
def test_show_only_own_snapshots(self):
|
||||||
|
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
||||||
|
"slug": self.slug
|
||||||
|
})
|
||||||
|
self.assertIsNone(result.get('errors'))
|
||||||
|
snapshots = result['data']['module']['snapshots']
|
||||||
|
self.assertEqual(len(snapshots), 1)
|
||||||
|
self.assertEqual(snapshots[0]['creator']['username'], 'teacher')
|
||||||
|
|
||||||
|
def test_share_snapshot(self):
|
||||||
|
self.assertFalse(self.snapshot.shared)
|
||||||
|
result = self.client.execute(SHARE_SNAPSHOT_MUTATION, variables={
|
||||||
|
'input': {
|
||||||
|
'snapshot': to_global_id('Snapshot', self.snapshot.id),
|
||||||
|
'shared': True
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.assertIsNone(result.get('errors'))
|
||||||
|
data = result['data']['shareSnapshot']
|
||||||
|
self.assertTrue(data['success'])
|
||||||
|
self.assertTrue(data['snapshot']['shared'])
|
||||||
|
snapshot = Snapshot.objects.get(pk=self.snapshot.pk)
|
||||||
|
self.assertTrue(snapshot.shared)
|
||||||
|
|
||||||
|
def test_dont_share_foreign_snapshot(self):
|
||||||
|
self.assertFalse(self.snapshot.shared)
|
||||||
|
teacher2_client = self.get_client(self.teacher2)
|
||||||
|
result = teacher2_client.execute(SHARE_SNAPSHOT_MUTATION, variables={
|
||||||
|
'input': {
|
||||||
|
'snapshot': to_global_id('Snapshot', self.snapshot.id),
|
||||||
|
'shared': True
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.assertIsNotNone(result.get('errors'))
|
||||||
Loading…
Reference in New Issue