Allow multiple teachers per school class
For that purpose, now the enabled solutions are stored on a per school class basis instead of a per teacher basis
This commit is contained in:
parent
0ac0f3d610
commit
ab9da652cf
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.1.15 on 2020-03-02 16:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0011_auto_20200302_1613'),
|
||||
('books', '0016_auto_20191128_1601'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='module',
|
||||
name='solutions_enabled_for',
|
||||
field=models.ManyToManyField(to='users.SchoolClass'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.1.15 on 2020-03-02 16:31
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0017_module_solutions_enabled_for'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='module',
|
||||
name='solutions_enabled_by',
|
||||
),
|
||||
]
|
||||
|
|
@ -7,7 +7,7 @@ from wagtail.images.edit_handlers import ImageChooserPanel
|
|||
|
||||
from books.blocks import DEFAULT_RICH_TEXT_FEATURES
|
||||
from core.wagtail_utils import StrictHierarchyPage
|
||||
from users.models import User
|
||||
from users.models import SchoolClass
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ class Module(StrictHierarchyPage):
|
|||
teaser = models.TextField()
|
||||
intro = RichTextField(features=DEFAULT_RICH_TEXT_FEATURES)
|
||||
|
||||
solutions_enabled_by = models.ManyToManyField(User)
|
||||
solutions_enabled_for = models.ManyToManyField(SchoolClass)
|
||||
|
||||
content_panels = [
|
||||
FieldPanel('title', classname="full title"),
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ class UpdateSolutionVisibility(relay.ClientIDMutation):
|
|||
slug = args.get('slug')
|
||||
enabled = args.get('enabled')
|
||||
user = info.context.user
|
||||
selected_class = user.selected_class()
|
||||
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
|
||||
raise PermissionError()
|
||||
|
||||
module = Module.objects.get(slug=slug)
|
||||
if enabled:
|
||||
module.solutions_enabled_by.add(user)
|
||||
module.solutions_enabled_for.add(selected_class)
|
||||
else:
|
||||
module.solutions_enabled_by.remove(user)
|
||||
module.solutions_enabled_for.remove(selected_class)
|
||||
module.save()
|
||||
|
||||
return cls(success=True, solutions_enabled=enabled)
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ class ModuleNode(DjangoObjectType):
|
|||
return self.get_parent().specific
|
||||
|
||||
def resolve_solutions_enabled(self, info, **kwargs):
|
||||
teacher = info.context.user.get_teacher()
|
||||
return self.solutions_enabled_by.filter(pk=teacher.pk).exists() if teacher is not None else False
|
||||
school_class = info.context.user.selected_class()
|
||||
return self.solutions_enabled_for.filter(pk=school_class.pk).exists() if school_class is not None else False
|
||||
|
||||
def resolve_bookmark(self, info, **kwags):
|
||||
return ModuleBookmark.objects.filter(
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ from graphene.test import Client
|
|||
from graphql_relay import to_global_id
|
||||
|
||||
from api.schema import schema
|
||||
from api.utils import get_graphql_mutation
|
||||
|
||||
from books.factories import BookFactory, TopicFactory, ModuleFactory, ChapterFactory, ContentBlockFactory
|
||||
from books.models import ContentBlock
|
||||
from books.factories import BookFactory, ContentBlockFactory
|
||||
from users.models import User
|
||||
from users.services import create_users
|
||||
|
||||
|
|
@ -30,6 +30,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
)
|
||||
|
||||
self.teacher = User.objects.get(username="teacher")
|
||||
self.selected_class = self.teacher.selected_class()
|
||||
self.student = User.objects.get(username="student1")
|
||||
student_request = RequestFactory().get('/')
|
||||
student_request.user = self.student
|
||||
|
|
@ -41,13 +42,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
|
||||
self.content_block_id = to_global_id('ContentBlockNode', content_block.pk)
|
||||
|
||||
self.update_mutation = mutation = """
|
||||
mutation UpdateSolutionVisibility($input: UpdateSolutionVisibilityInput!) {
|
||||
updateSolutionVisibility(input: $input) {
|
||||
success
|
||||
}
|
||||
}
|
||||
"""
|
||||
self.update_mutation = get_graphql_mutation('updateSolutionVisibility.gql')
|
||||
|
||||
self.query = """
|
||||
query ContentBlockQuery($id: ID!) {
|
||||
|
|
@ -59,6 +54,8 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
"""
|
||||
|
||||
def test_hide_solutions_for_students_and_then_show_them(self):
|
||||
self.assertEqual(self.student.selected_class(), self.teacher.selected_class())
|
||||
|
||||
result = self.student_client.execute(self.query, variables={
|
||||
'id': self.content_block_id
|
||||
})
|
||||
|
|
@ -70,7 +67,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
'id': self.content_block_id
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('contentBlock').get('contents')), 1)
|
||||
self.assertEqual(len(result.get('data').get('contentBlock').get('contents')), 0)
|
||||
|
||||
result = self.teacher_client.execute(self.update_mutation, variables={
|
||||
'input': {
|
||||
|
|
@ -81,7 +78,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
|||
|
||||
self.assertEqual(result.get('data').get('updateSolutionVisibility').get('success'), True)
|
||||
|
||||
self.assertEqual(self.module.solutions_enabled_by.filter(pk=self.teacher.pk).count(), 1)
|
||||
self.assertEqual(self.module.solutions_enabled_for.filter(pk=self.selected_class.pk).count(), 1)
|
||||
|
||||
result = self.student_client.execute(self.query, variables={
|
||||
'id': self.content_block_id
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ from users.models import User, Role
|
|||
|
||||
def are_solutions_enabled_for(user: User, module: Module):
|
||||
teacher = user.users_in_same_school_class().filter(user_roles__role=Role.objects.get_default_teacher_role()).first()
|
||||
return 'users.can_manage_school_class_content' in user.get_role_permissions() or user.is_superuser or (
|
||||
teacher is not None and module.solutions_enabled_by.filter(pk=teacher.pk).exists())
|
||||
school_class = user.selected_class()
|
||||
return module.solutions_enabled_for.filter(pk=school_class.pk).exists()
|
||||
|
||||
|
||||
def get_type_and_value(data):
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ class Command(BaseCommand):
|
|||
self.stdout.write("Hiding solutions")
|
||||
for module in Module.objects.all():
|
||||
self.stdout.write("Hiding solutions in module {}.".format(module.title))
|
||||
module.solutions_enabled_by.clear()
|
||||
module.solutions_enabled_for.clear()
|
||||
self.stdout.write("Hiding done")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.1.15 on 2020-03-02 16:13
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rooms', '0007_auto_20190808_0649'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='moduleroomslug',
|
||||
options={'verbose_name': 'Slug für Modul-Raum', 'verbose_name_plural': 'Slugs für Modul-Raum'},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.1.15 on 2020-03-02 16:13
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0010_schoolclass_code'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='schoolclass',
|
||||
options={'verbose_name': 'Schulklasse', 'verbose_name_plural': 'Schulklassen'},
|
||||
),
|
||||
]
|
||||
Loading…
Reference in New Issue