diff --git a/server/assignments/migrations/0017_alter_assignment_module.py b/server/assignments/migrations/0017_alter_assignment_module.py new file mode 100644 index 00000000..f9bcebc4 --- /dev/null +++ b/server/assignments/migrations/0017_alter_assignment_module.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.16 on 2023-04-12 14:01 + +from django.db import migrations +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('books', '0042_alter_contentblock_contents'), + ('assignments', '0016_alter_assignment_options'), + ] + + operations = [ + migrations.AlterField( + model_name='assignment', + name='module', + field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.PROTECT, related_name='assignments', to='books.module'), + ), + ] diff --git a/server/assignments/models.py b/server/assignments/models.py index 7cca5e3a..96452da9 100644 --- a/server/assignments/models.py +++ b/server/assignments/models.py @@ -9,6 +9,7 @@ from wagtail.search import index from core.constants import DEFAULT_RICH_TEXT_FEATURES from django.utils.translation import ugettext_lazy as _ +from modelcluster.fields import ParentalKey @register_snippet @@ -17,53 +18,69 @@ class Assignment(index.Indexed, TimeStampedModel): assignment = RichTextField(features=DEFAULT_RICH_TEXT_FEATURES) solution = RichTextField(null=True, blank=True, features=DEFAULT_RICH_TEXT_FEATURES) deleted = models.BooleanField(default=False) - owner = models.ForeignKey(get_user_model(), - on_delete=models.PROTECT, null=True, - blank=True) # probably don't want to delete all assignments if a user gets deleted - module = models.ForeignKey('books.Module', related_name='assignments', on_delete=models.CASCADE) + owner = models.ForeignKey( + get_user_model(), on_delete=models.PROTECT, null=True, blank=True + ) # probably don't want to delete all assignments if a user gets deleted + module = ParentalKey( + "books.Module", related_name="assignments", on_delete=models.PROTECT + ) user_created = models.BooleanField(default=False) taskbase_id = models.CharField(max_length=255, null=True, blank=True) search_fields = [ - index.SearchField('title', partial_match=True), - index.SearchField('assignment', partial_match=True), + index.SearchField("title", partial_match=True), + index.SearchField("assignment", partial_match=True), ] panels = [ - FieldPanel('title'), - FieldPanel('assignment'), - FieldPanel('solution'), - FieldPanel('module'), - AutocompletePanel('owner') + FieldPanel("title"), + FieldPanel("assignment"), + FieldPanel("solution"), + FieldPanel("module"), + AutocompletePanel("owner"), ] def __str__(self): - return self.title if not self.user_created else '{} (erstellt von {})'.format(self.title, self.owner) + return ( + self.title + if not self.user_created + else "{} (erstellt von {})".format(self.title, self.owner) + ) class Meta: - verbose_name = _('assignment') - verbose_name_plural = _('assignments') - ordering = ['-created'] + verbose_name = _("assignment") + verbose_name_plural = _("assignments") + ordering = ["-created"] class StudentSubmission(TimeStampedModel): text = models.TextField(blank=True) - document = models.URLField(blank=True, default='', max_length=255) - assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE, related_name='submissions') - student = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='submissions') + document = models.URLField(blank=True, default="", max_length=255) + assignment = models.ForeignKey( + Assignment, on_delete=models.CASCADE, related_name="submissions" + ) + student = models.ForeignKey( + get_user_model(), on_delete=models.CASCADE, related_name="submissions" + ) final = models.BooleanField(default=False) def __str__(self): - return '{} - {}'.format(self.student.full_name, self.text) + return "{} - {}".format(self.student.full_name, self.text) class SubmissionFeedback(TimeStampedModel): text = models.TextField(blank=True) # teacher who created the feedback - teacher = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='feedbacks') - student_submission = models.OneToOneField(StudentSubmission, on_delete=models.CASCADE, primary_key=True, - related_name='submission_feedback') + teacher = models.ForeignKey( + get_user_model(), on_delete=models.CASCADE, related_name="feedbacks" + ) + student_submission = models.OneToOneField( + StudentSubmission, + on_delete=models.CASCADE, + primary_key=True, + related_name="submission_feedback", + ) final = models.BooleanField(default=False) def __str__(self): - return '{} - {}'.format(self.student_submission.student.full_name, self.text) + return "{} - {}".format(self.student_submission.student.full_name, self.text) diff --git a/server/basicknowledge/migrations/0027_alter_basicknowledge_contents.py b/server/basicknowledge/migrations/0027_alter_basicknowledge_contents.py new file mode 100644 index 00000000..5ef5d142 --- /dev/null +++ b/server/basicknowledge/migrations/0027_alter_basicknowledge_contents.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.16 on 2023-04-12 14:01 + +import books.blocks +from django.db import migrations +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('basicknowledge', '0026_alter_basicknowledge_contents'), + ] + + operations = [ + migrations.AlterField( + model_name='basicknowledge', + name='contents', + field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/server/books/migrations/0042_alter_contentblock_contents.py b/server/books/migrations/0042_alter_contentblock_contents.py new file mode 100644 index 00000000..a1442da6 --- /dev/null +++ b/server/books/migrations/0042_alter_contentblock_contents.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.16 on 2023-04-12 14:01 + +import assignments.models +import books.blocks +from django.db import migrations +import surveys.models +import wagtail.blocks +import wagtail.documents.blocks +import wagtail.fields +import wagtail.images.blocks +import wagtail.snippets.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('books', '0041_alter_contentblock_contents'), + ] + + operations = [ + migrations.AlterField( + model_name='contentblock', + name='contents', + field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock()), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())]))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/server/books/models/module.py b/server/books/models/module.py index abcddfe1..91a8c8fa 100644 --- a/server/books/models/module.py +++ b/server/books/models/module.py @@ -1,7 +1,8 @@ from django.db import models from django.utils import timezone -from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList +from wagtail.admin.panels import FieldPanel, InlinePanel, TabbedInterface, ObjectList from wagtail.fields import RichTextField +from django.utils.translation import ugettext_lazy as _ from core.constants import DEFAULT_RICH_TEXT_FEATURES from core.wagtail_utils import StrictHierarchyPage, get_default_settings @@ -13,8 +14,7 @@ class Module(StrictHierarchyPage): verbose_name = "Modul" verbose_name_plural = "Module" - meta_title = models.CharField( - max_length=255, help_text="e.g. 'Intro' or 'Modul 1'") + meta_title = models.CharField(max_length=255, help_text="e.g. 'Intro' or 'Modul 1'") hero_image = models.ForeignKey( "wagtailimages.Image", null=True, @@ -38,6 +38,26 @@ class Module(StrictHierarchyPage): FieldPanel("hero_source"), FieldPanel("teaser"), FieldPanel("intro"), + InlinePanel( + "assignments", + label=_("Assignment"), + classname="collapsed", + heading=_("linked assignments"), + help_text=_( + "These %s are automatically linked, they are shown here only to provide an overview. Please don't change anything here." + ) + % _("assignments"), + ), + InlinePanel( + "surveys", + heading=_("linked surveys"), + label=_("Survey"), + classname="collapsed", + help_text=_( + "These %s are automatically linked, they are shown here only to provide an overview. Please don't change anything here." + ) + % _("surveys"), + ), ] edit_handler = TabbedInterface( @@ -92,8 +112,7 @@ class Module(StrictHierarchyPage): content_block.visible_for.add(school_class_to_sync) for chapter in chapters: - chapter.sync_title_visibility( - school_class_template, school_class_to_sync) + chapter.sync_title_visibility(school_class_template, school_class_to_sync) chapter.sync_description_visibility( school_class_template, school_class_to_sync ) @@ -101,8 +120,7 @@ class Module(StrictHierarchyPage): objective_groups = self.objective_groups.all() for objective_group in objective_groups: - objective_group.sync_visibility( - school_class_template, school_class_to_sync) + objective_group.sync_visibility(school_class_template, school_class_to_sync) def get_admin_display_title(self): return f"{self.meta_title} - {self.title}" diff --git a/server/core/urls.py b/server/core/urls.py index 6689dd5a..5e2cfc2a 100644 --- a/server/core/urls.py +++ b/server/core/urls.py @@ -15,21 +15,20 @@ from core.views import override_wagtailadmin_explore_default_ordering urlpatterns = [ # django admin - url(r'^guru/', admin.site.urls), - url(r'^statistics/', include('statistics.urls', namespace='statistics')), - + url(r"^guru/", admin.site.urls), + url(r"^statistics/", include("statistics.urls", namespace="statistics")), # wagtail - url(r'^admin/autocomplete/', include(autocomplete_admin_urls)), - re_path(r'^cms/pages/(\d+)/$', override_wagtailadmin_explore_default_ordering), - url(r'^cms/', include(wagtailadmin_urls)), - url(r'^documents/', include(wagtaildocs_urls)), - + url(r"^cms/autocomplete/", include(autocomplete_admin_urls)), + re_path(r"^cms/pages/(\d+)/$", override_wagtailadmin_explore_default_ordering), + url(r"^cms/", include(wagtailadmin_urls)), + url(r"^documents/", include(wagtaildocs_urls)), # graphql backend - url(r'^api/', include('api.urls', namespace="api")), - - #favicon - url(r'^favicon\.ico$', RedirectView.as_view(url='/static/favicon@2x.png', permanent=True)), - + url(r"^api/", include("api.urls", namespace="api")), + # favicon + url( + r"^favicon\.ico$", + RedirectView.as_view(url="/static/favicon@2x.png", permanent=True), + ), ] if settings.DEBUG and not settings.USE_AWS: @@ -39,11 +38,13 @@ if settings.DEBUG: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) if settings.ENABLE_SILKY: - urlpatterns += [url(r'^silk/', include('silk.urls', namespace='silk'))] + urlpatterns += [url(r"^silk/", include("silk.urls", namespace="silk"))] # actually we use the cms in headless mode but need the url pattern to get the wagtail_serve function -urlpatterns += [url(r'pages/', include(wagtail_urls)), ] +urlpatterns += [ + url(r"pages/", include(wagtail_urls)), +] -urlpatterns += [re_path(r'^.*$', views.home, name='home')] +urlpatterns += [re_path(r"^.*$", views.home, name="home")] -admin.site.site_header = 'Myskillbox Admin' +admin.site.site_header = "Myskillbox Admin" diff --git a/server/locale/de/LC_MESSAGES/django.mo b/server/locale/de/LC_MESSAGES/django.mo index a3b684bc..4d9d8291 100644 Binary files a/server/locale/de/LC_MESSAGES/django.mo and b/server/locale/de/LC_MESSAGES/django.mo differ diff --git a/server/locale/de/LC_MESSAGES/django.po b/server/locale/de/LC_MESSAGES/django.po index eb087fc0..b92605b6 100644 --- a/server/locale/de/LC_MESSAGES/django.po +++ b/server/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-14 13:57+0000\n" +"POT-Creation-Date: 2023-04-12 13:50+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,43 +18,80 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: assignments/models.py:44 +#: assignments/models.py:51 msgid "assignment" -msgstr "auftrag" +msgstr "Auftrag" -#: assignments/models.py:45 +#: assignments/models.py:52 books/models/module.py:49 msgid "assignments" -msgstr "aufträge" +msgstr "Aufträge" -#: basicknowledge/models.py:31 +#: basicknowledge/models.py:40 msgid "instrument categories" msgstr "instrumentkategorien" -#: basicknowledge/models.py:32 +#: basicknowledge/models.py:41 msgid "instrument category" msgstr "instrumentkategorie" -#: basicknowledge/models.py:41 +#: basicknowledge/models.py:50 +#, fuzzy +#| msgid "instrument category" +msgid "instrument type" +msgstr "instrumenttyp" + +#: basicknowledge/models.py:51 msgid "instrument types" msgstr "instrumenttypen" -#: basicknowledge/models.py:69 +#: basicknowledge/models.py:78 msgid "instrument" msgstr "instrument" -#: basicknowledge/models.py:70 +#: basicknowledge/models.py:79 msgid "instruments" msgstr "instrumente" -#: basicknowledge/wagtail_hooks.py:25 +#: basicknowledge/wagtail_hooks.py:41 msgid "Instruments" msgstr "Instrumente" -#: core/settings.py:197 +#: books/models/module.py:43 +msgid "Assignment" +msgstr "Auftrag" + +#: books/models/module.py:45 +#| msgid "assignments" +msgid "linked assignments" +msgstr "Verlinkte Aufträge" + +#: books/models/module.py:47 books/models/module.py:57 +#, python-format +msgid "" +"These %s are automatically linked, they are shown here only to provide an " +"overview. Please don't change anything here." +msgstr "" +"Diese %s sind automatisch verlinkt, sie werden hier als Übersicht angezeigt. " +"Bitte hier nichts verändern." + +#: books/models/module.py:53 +#| msgid "surveys" +msgid "linked surveys" +msgstr "Verlinkte Surveys" + +#: books/models/module.py:54 +msgid "Survey" +msgstr "Survey" + +#: books/models/module.py:59 +msgid "surveys" +msgstr "Übungen" + +#: core/settings.py:193 msgid "German" msgstr "" -#: core/settings.py:198 +#: core/settings.py:194 msgid "English" msgstr "" @@ -330,10 +367,8 @@ msgstr "" msgid "Das alte Passwort muss angegeben werden" msgstr "" -#, fuzzy -#~| msgid "instrument category" -#~ msgid "instrument type" -#~ msgstr "instrumenttyp" +#~ msgid "Assignments" +#~ msgstr "Aufträge" -#~ msgid "assignmentsss" -#~ msgstr "aufträge" +#~ msgid "Surveys" +#~ msgstr "Surveys" diff --git a/server/rooms/migrations/0014_alter_roomentry_contents.py b/server/rooms/migrations/0014_alter_roomentry_contents.py new file mode 100644 index 00000000..cba8e82b --- /dev/null +++ b/server/rooms/migrations/0014_alter_roomentry_contents.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.16 on 2023-04-12 14:01 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('rooms', '0013_alter_roomentry_contents'), + ] + + operations = [ + migrations.AlterField( + model_name='roomentry', + name='contents', + field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript']))])), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())]))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/server/surveys/migrations/0007_alter_survey_module.py b/server/surveys/migrations/0007_alter_survey_module.py new file mode 100644 index 00000000..6fd87113 --- /dev/null +++ b/server/surveys/migrations/0007_alter_survey_module.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.16 on 2023-04-12 14:01 + +from django.db import migrations +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('books', '0042_alter_contentblock_contents'), + ('surveys', '0006_auto_20230214_1415'), + ] + + operations = [ + migrations.AlterField( + model_name='survey', + name='module', + field=modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='surveys', to='books.module'), + ), + ] diff --git a/server/surveys/models.py b/server/surveys/models.py index b869272d..2c226cff 100644 --- a/server/surveys/models.py +++ b/server/surveys/models.py @@ -3,12 +3,13 @@ from django.db import models from django.db.models import JSONField from wagtail.snippets.models import register_snippet from wagtail.search import index +from modelcluster.fields import ParentalKey @register_snippet class Survey(models.Model, index.Indexed): title = models.CharField(max_length=255) - module = models.ForeignKey( + module = ParentalKey( "books.Module", related_name="surveys", on_delete=models.PROTECT, @@ -34,8 +35,7 @@ class Answer(models.Model): get_user_model(), on_delete=models.CASCADE, related_name="answers" ) data = JSONField() - survey = models.ForeignKey( - Survey, on_delete=models.PROTECT, related_name="answers") + survey = models.ForeignKey(Survey, on_delete=models.PROTECT, related_name="answers") def __str__(self): return "{} - {}".format(self.owner.username, self.survey.title)