diff --git a/server/api/schema.py b/server/api/schema.py index 2c7fe233..f069301f 100644 --- a/server/api/schema.py +++ b/server/api/schema.py @@ -8,7 +8,7 @@ from api import graphene_wagtail from book.schema.mutations import BookMutations -from book.schema.queries import BookQuery +from filteredbook.schema import BookQuery from objectives.schema import ObjectivesQuery from rooms.schema import RoomsQuery diff --git a/server/book/migrations/0001_initial.py b/server/book/migrations/0001_initial.py index 07e54957..07e4b43c 100644 --- a/server/book/migrations/0001_initial.py +++ b/server/book/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-09-04 13:55 +# Generated by Django 2.0.6 on 2018-09-11 14:14 from django.db import migrations, models import django.db.models.deletion @@ -43,8 +43,8 @@ class Migration(migrations.Migration): name='ContentBlock', fields=[ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), - ('contents', wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='doc-full')), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('url', wagtail.core.blocks.URLBlock())], icon='placeholder')), ('student_entry', wagtail.core.blocks.StructBlock([('task_text', wagtail.core.blocks.RichTextBlock())], icon='download')), ('image_block', wagtail.images.blocks.ImageChooserBlock(icon='image')), ('task', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick'))], blank=True, null=True)), - ('type', models.CharField(choices=[('plain', 'Normal'), ('yellow', 'Gelb'), ('green', 'Grün'), ('blue', 'Blau')], max_length=100)), + ('contents', wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='doc-full')), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('url', wagtail.core.blocks.URLBlock())], icon='placeholder')), ('student_entry', wagtail.core.blocks.StructBlock([('task_text', wagtail.core.blocks.RichTextBlock())], icon='download')), ('image_block', wagtail.images.blocks.ImageChooserBlock(icon='image')), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())], icon='link')), ('task', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick'))], blank=True, null=True)), + ('type', models.CharField(choices=[('plain', 'Normal'), ('yellow', 'Gelb'), ('green', 'Grün'), ('blue', 'Blau')], default='plain', max_length=100)), ], options={ 'verbose_name': 'Inhaltsblock', diff --git a/server/book/models/contentblock.py b/server/book/models/contentblock.py index 33bc4d23..4625b2e6 100644 --- a/server/book/models/contentblock.py +++ b/server/book/models/contentblock.py @@ -7,6 +7,7 @@ from wagtail.images.blocks import ImageChooserBlock from book.blocks import TextBlock, BasicKnowledgeBlock, StudentEntryBlock, LinkBlock from core.wagtail_utils import StrictHierarchyPage +from user.models import UserGroup logger = logging.getLogger(__name__) diff --git a/server/book/schema/queries.py b/server/book/schema/queries.py index fec277c5..f62415dc 100644 --- a/server/book/schema/queries.py +++ b/server/book/schema/queries.py @@ -104,27 +104,3 @@ class BookNode(DjangoObjectType): def resolve_topics(self, *args, **kwargs): return Topic.get_by_parent(self) - - -class BookQuery(object): - book = relay.Node.Field(BookNode) - topic = relay.Node.Field(TopicNode) - module = relay.Node.Field(ModuleNode) - chapter = relay.Node.Field(ChapterNode) - - books = DjangoFilterConnectionField(BookNode) - topics = DjangoFilterConnectionField(TopicNode) - modules = DjangoFilterConnectionField(ModuleNode) - chapters = DjangoFilterConnectionField(ChapterNode) - - def resolve_books(self, *args, **kwargs): - return Book.objects.filter(**kwargs).live() - - def resolve_topics(self, *args, **kwargs): - return Topic.objects.filter(**kwargs).live() - - def resolve_modules(self, *args, **kwargs): - return Module.objects.filter(**kwargs).live() - - def resolve_chapters(self, *args, **kwargs): - return Chapter.objects.filter(**kwargs).live() diff --git a/server/core/settings.py b/server/core/settings.py index 0bd059d0..4dd9e1a1 100644 --- a/server/core/settings.py +++ b/server/core/settings.py @@ -49,6 +49,7 @@ INSTALLED_APPS = [ 'book', 'objectives', 'rooms', + 'filteredbook', 'wagtail.contrib.forms', 'wagtail.contrib.redirects', diff --git a/server/filteredbook/__init__.py b/server/filteredbook/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/filteredbook/admin.py b/server/filteredbook/admin.py new file mode 100644 index 00000000..953cbb3e --- /dev/null +++ b/server/filteredbook/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from filteredbook.models import Visibility + + +@admin.register(Visibility) +class VisibilityAdmin(admin.ModelAdmin): + list_display = ('user_group', 'content_block') + list_filter = ('user_group', 'content_block') diff --git a/server/filteredbook/apps.py b/server/filteredbook/apps.py new file mode 100644 index 00000000..83a31e1f --- /dev/null +++ b/server/filteredbook/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class FilteredbookConfig(AppConfig): + name = 'filteredbook' diff --git a/server/filteredbook/migrations/0001_initial.py b/server/filteredbook/migrations/0001_initial.py new file mode 100644 index 00000000..a8ea65c1 --- /dev/null +++ b/server/filteredbook/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 2.0.6 on 2018-09-11 14:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('book', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Visibility', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content_block', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='book.ContentBlock')), + ], + options={ + 'verbose_name': 'Visibility', + 'verbose_name_plural': 'Visibilities', + }, + ), + ] diff --git a/server/filteredbook/migrations/0002_visibility_user_group.py b/server/filteredbook/migrations/0002_visibility_user_group.py new file mode 100644 index 00000000..a9aa20f2 --- /dev/null +++ b/server/filteredbook/migrations/0002_visibility_user_group.py @@ -0,0 +1,22 @@ +# Generated by Django 2.0.6 on 2018-09-11 14:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('filteredbook', '0001_initial'), + ('user', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='visibility', + name='user_group', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='user.UserGroup'), + ), + ] diff --git a/server/filteredbook/migrations/__init__.py b/server/filteredbook/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/filteredbook/models.py b/server/filteredbook/models.py new file mode 100644 index 00000000..f35ffb01 --- /dev/null +++ b/server/filteredbook/models.py @@ -0,0 +1,16 @@ +from django.db import models + +from book.models import ContentBlock +from user.models import UserGroup + + +class Visibility(models.Model): + class Meta: + verbose_name = 'Visibility' + verbose_name_plural = 'Visibilities' + + user_group = models.ForeignKey(UserGroup, blank=False, null=False, on_delete=models.CASCADE) + content_block = models.ForeignKey(ContentBlock, blank=False, null=False, on_delete=models.CASCADE) + + def __str__(self): + return 'Visibility {}-{}'.format(self.user_group, self.content_block) diff --git a/server/filteredbook/schema.py b/server/filteredbook/schema.py new file mode 100644 index 00000000..12892c69 --- /dev/null +++ b/server/filteredbook/schema.py @@ -0,0 +1,63 @@ +from itertools import chain + +import graphene +from django.db.models import Q +from graphene import relay +from graphene_django import DjangoObjectType +from graphene_django.filter import DjangoFilterConnectionField + +from book.models import Book, Topic, Module, Chapter, ContentBlock +from book.schema.queries import BookNode, TopicNode, ModuleNode, ContentBlockNode + + +class FilteredChapterNode(DjangoObjectType): + content_blocks = DjangoFilterConnectionField(ContentBlockNode, user_groups=graphene.List(graphene.String)) + + class Meta: + model = Chapter + only_fields = [ + 'slug', 'title', + ] + filter_fields = [ + 'slug', 'title', + ] + interfaces = (relay.Node,) + + def resolve_content_blocks(self, *args, **kwargs): + user_groups = kwargs.get('user_groups') + if user_groups: + reduced = [] + for user_group in user_groups: + content_blocks = ContentBlock.get_by_parent(self).exclude( + Q(visibility__user_group__name=user_group) + ) + reduced = chain(reduced, content_blocks) + + filtered = list(set(reduced)) + return filtered + else: + return ContentBlock.get_by_parent(self) + + +class BookQuery(object): + book = relay.Node.Field(BookNode) + topic = relay.Node.Field(TopicNode) + module = relay.Node.Field(ModuleNode) + chapter = relay.Node.Field(FilteredChapterNode) + + books = DjangoFilterConnectionField(BookNode) + topics = DjangoFilterConnectionField(TopicNode) + modules = DjangoFilterConnectionField(ModuleNode) + chapters = DjangoFilterConnectionField(FilteredChapterNode) + + def resolve_books(self, *args, **kwargs): + return Book.objects.filter(**kwargs).live() + + def resolve_topics(self, *args, **kwargs): + return Topic.objects.filter(**kwargs).live() + + def resolve_modules(self, *args, **kwargs): + return Module.objects.filter(**kwargs).live() + + def resolve_chapters(self, *args, **kwargs): + return Chapter.objects.filter(**kwargs).live() diff --git a/server/objectives/migrations/0001_initial.py b/server/objectives/migrations/0001_initial.py index edfc7e15..948e8d57 100644 --- a/server/objectives/migrations/0001_initial.py +++ b/server/objectives/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-09-04 13:55 +# Generated by Django 2.0.6 on 2018-09-11 14:14 from django.db import migrations, models import django.db.models.deletion diff --git a/server/objectives/migrations/0002_auto_20180904_1355.py b/server/objectives/migrations/0002_auto_20180911_1414.py similarity index 96% rename from server/objectives/migrations/0002_auto_20180904_1355.py rename to server/objectives/migrations/0002_auto_20180911_1414.py index 97825643..28647a1d 100644 --- a/server/objectives/migrations/0002_auto_20180904_1355.py +++ b/server/objectives/migrations/0002_auto_20180911_1414.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-09-04 13:55 +# Generated by Django 2.0.6 on 2018-09-11 14:14 from django.conf import settings from django.db import migrations, models @@ -10,8 +10,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('book', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('objectives', '0001_initial'), ] diff --git a/server/rooms/migrations/0001_initial.py b/server/rooms/migrations/0001_initial.py index 28166a1c..11d47954 100644 --- a/server/rooms/migrations/0001_initial.py +++ b/server/rooms/migrations/0001_initial.py @@ -1,10 +1,9 @@ -# Generated by Django 2.0.6 on 2018-09-04 13:55 +# Generated by Django 2.0.6 on 2018-09-11 14:14 from django.db import migrations, models import django_extensions.db.fields import wagtail.core.blocks import wagtail.core.fields -import wagtail.images.blocks class Migration(migrations.Migration): @@ -37,7 +36,7 @@ class Migration(migrations.Migration): ('description', models.TextField(blank=True, null=True, verbose_name='description')), ('slug', django_extensions.db.fields.AutoSlugField(blank=True, editable=False, populate_from='title', verbose_name='slug')), ('subtitle', models.CharField(blank=True, max_length=255)), - ('contents', wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='doc-full')), ('image_url', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.RichTextBlock()), ('url', wagtail.core.blocks.URLBlock())], icon='image')), ('image_block', wagtail.images.blocks.ImageChooserBlock(icon='image'))], blank=True, null=True)), + ('contents', wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='doc-full')), ('image_url', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.RichTextBlock()), ('url', wagtail.core.blocks.URLBlock())], icon='image')), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())], icon='link'))], blank=True, null=True)), ], options={ 'verbose_name': 'Raumeintrag', diff --git a/server/rooms/migrations/0002_auto_20180904_1355.py b/server/rooms/migrations/0002_auto_20180911_1414.py similarity index 95% rename from server/rooms/migrations/0002_auto_20180904_1355.py rename to server/rooms/migrations/0002_auto_20180911_1414.py index a3ecdf5a..ca05b3ef 100644 --- a/server/rooms/migrations/0002_auto_20180904_1355.py +++ b/server/rooms/migrations/0002_auto_20180911_1414.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-09-04 13:55 +# Generated by Django 2.0.6 on 2018-09-11 14:14 from django.conf import settings from django.db import migrations, models @@ -10,9 +10,9 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('user', '0001_initial'), ('rooms', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('user', '0001_initial'), ] operations = [ diff --git a/server/rooms/models.py b/server/rooms/models.py index 1e1384f7..a62ef5d0 100644 --- a/server/rooms/models.py +++ b/server/rooms/models.py @@ -2,7 +2,6 @@ from django.contrib.auth import get_user_model from django.db import models from django_extensions.db.models import TitleDescriptionModel, TitleSlugDescriptionModel from wagtail.core.fields import StreamField -from wagtail.images.blocks import ImageChooserBlock from book.blocks import ImageUrlBlock, LinkBlock from book.models import ContentBlock, TextBlock diff --git a/server/user/migrations/0001_initial.py b/server/user/migrations/0001_initial.py index b6f2db0e..412c2ded 100644 --- a/server/user/migrations/0001_initial.py +++ b/server/user/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-09-04 13:55 +# Generated by Django 2.0.6 on 2018-09-11 14:14 from django.conf import settings import django.contrib.auth.models