Merge branch 'release/Wagtail-anpassungen' into develop

# Conflicts:
#	server/core/settings.py
#	server/users/migrations/0032_alter_license_isbn.py
This commit is contained in:
Lorenz Padberg 2022-08-03 14:34:54 +02:00
commit c432825aa8
33 changed files with 80972 additions and 16 deletions

1
.gitignore vendored
View File

@ -47,3 +47,4 @@ server/media/
# test reports
client/cypress/test-reports/
server/test-reports/
.direnv

View File

@ -0,0 +1,45 @@
<template>
<div class="cms-document-block">
<document-icon class="cms-document-block__icon" />
<a
:href="value.url"
class="cms-document-block__link"
target="_blank"
>{{ value.display_text }}</a>
</div>
</template>
<script>
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
export default {
props: {
value: Object,
},
components: {
DocumentIcon,
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
.cms-document-block {
display: grid;
grid-template-columns: 50px 1fr 50px;
align-items: center;
margin-bottom: $large-spacing;
&__icon {
width: 30px;
height: 30px;
}
&__link {
text-decoration: underline;
}
}
</style>

View File

@ -31,6 +31,7 @@ const ImageUrlBlock = () => import(/* webpackChunkName: "content-components" */'
const VideoBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/VideoBlock');
const LinkBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/LinkBlock');
const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock');
const CmsDocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/CmsDocumentBlock');
const InfogramBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InfogramBlock');
const ThinglinkBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ThinglinkBlock');
const GeniallyBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/GeniallyBlock');
@ -88,6 +89,7 @@ export default {
'content_list': ContentListBlock,
'module_room_slug': ModuleRoomSlug,
'thinglink_block': ThinglinkBlock,
'cms_document_block': CmsDocumentBlock,
Survey,
Solution,
Instruction,

View File

@ -20,10 +20,12 @@
</script>
<style scoped lang="scss">
@import "~styles/helpers";
.image-block {
width: 100%;
max-width: 100%;
border-radius: 13px;
margin-bottom: 30px;
margin-bottom: $large-spacing;
}
</style>

View File

@ -24,3 +24,24 @@ To see the backup schedule
To download a backup use
`heroku pg:backups:download --app <appname>`
### Load a backup locally
Be careful since you download user data as well. Therefore use preprod app by
default, it is anonymized.
####Download backup
`heroku pg:backups:download --app <appname>`
####Load dump file into your db
To download a backup
`pg_restore --verbose --clean --no-acl --no-owner -h localhost -U skillbox -d skillbox latest.dump`
Add
python manage.py migrate
python manage.py dummy_users

View File

@ -6,10 +6,12 @@ from graphene.types import Scalar
from graphene_django.converter import convert_django_field
from graphql_relay import to_global_id
from wagtail.core.fields import StreamField
from wagtail.documents.models import Document
from wagtail.images.models import Image
from assignments.models import Assignment
from basicknowledge.models import BasicKnowledge
from books.models import CustomDocument
from surveys.models import Survey
logger = logging.getLogger(__name__)
@ -85,6 +87,23 @@ def augment_fields(raw_data):
item_data = data['value']
data['value'] = augment_fields(item_data)
if _type == 'cms_document_block':
try:
_value = data['value']
document = CustomDocument.objects.get(id=_value)
value = {
'value': _value,
'id': document.id,
'file_name': document.filename,
'file_extension': document.file_extension,
'url': document.url,
'title': document.title,
'display_text': document.display_text
}
data['value'] = value
except CustomDocument.DoesNotExist:
logger.error('CustomDocument {} does not exist'.format(_value))
return raw_data

View File

@ -24,7 +24,8 @@ class Assignment(index.Indexed, TimeStampedModel):
taskbase_id = models.CharField(max_length=255, null=True, blank=True)
search_fields = [
index.SearchField('title', partial_match=True)
index.SearchField('title', partial_match=True),
index.SearchField('assignment', partial_match=True),
]
panels = [

View File

@ -5,7 +5,9 @@ from .models import Assignment
class AssignmentAdmin(ModelAdmin):
model = Assignment
menu_label = 'Assignments'
list_display = ('title', 'module', 'pk',)
list_display = ('title', 'module', 'assignment')
search_fields = ('title', 'assignment')
menu_icon = 'form'
modeladmin_register(AssignmentAdmin)

View File

@ -0,0 +1,22 @@
# Generated by Django 3.2.13 on 2022-07-28 08:48
from django.db import migrations
import wagtail.core.blocks
import wagtail.core.fields
import wagtail.documents.blocks
import wagtail.images.blocks
class Migration(migrations.Migration):
dependencies = [
('basicknowledge', '0017_auto_20220630_0743'),
]
operations = [
migrations.AlterField(
model_name='basicknowledge',
name='contents',
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('section_title', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock())], blank=True, null=True),
),
]

View File

@ -2,6 +2,7 @@ from django.db import models
from django.utils.text import slugify
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
from wagtail.core.fields import RichTextField, StreamField
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.images.blocks import ImageChooserBlock
from books.blocks import DocumentBlock, GeniallyBlock, InfogramBlock, InstrumentTextBlock, LinkBlock, SectionTitleBlock, \
@ -35,6 +36,7 @@ class InstrumentType(models.Model):
return self.type
class BasicKnowledge(StrictHierarchyPage):
parent_page_types = ['books.book']
@ -51,6 +53,7 @@ class BasicKnowledge(StrictHierarchyPage):
('genially_block', GeniallyBlock()),
('thinglink_block', ThinglinkBlock()),
('subtitle', SubtitleBlock()),
('cms_document_block', DocumentChooserBlock()),
], null=True, blank=True)
new_type = models.ForeignKey(InstrumentType, null=True, on_delete=models.PROTECT, related_name='instruments')

View File

@ -5,7 +5,8 @@ from .models import BasicKnowledge
class InstrumentAdmin(ModelAdmin):
model = BasicKnowledge
menu_label = 'Instruments'
list_display = ('title', 'new_type')
list_display = ('title', 'new_type', 'status_string')
search_fields = ('title', 'new_type__name')
modeladmin_register(InstrumentAdmin)

View File

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
#
# Iterativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2015 Iterativ GmbH. All rights reserved.
#
# Created on 2022-08-02
# @author: lorenz.padberg@iterativ.ch

View File

@ -0,0 +1,14 @@
from django.core.management import BaseCommand
from books.migrate_document_model import migrate_documents_to_custom_document_model
from books.models import Module
from surveys.models import Survey
class Command(BaseCommand):
def handle(self, *args, **options):
self.stdout.write("Migrating Wagtail documents to Custommyskillbox documents")
migrate_documents_to_custom_document_model()
self.stdout.write("Finish migration")

View File

@ -0,0 +1,42 @@
from .models.custom_document import CustomDocument
def migrate_documents_to_custom_document_model(dryrun=False):
try:
from wagtail.documents.models import Document
all_documents = Document.objects.all()
except Exception as e:
# new databases do not have the table for the standart wagtail documents there fore the migration is not
# necessary. Mainly
return
print(f"Found {all_documents.count()} Documents")
for document in all_documents:
tags = document.title.replace(':', '').split(' ')
if dryrun:
print('')
print(document.title)
print(tags)
print(document.created_at)
print(document.url)
print(document.file)
print(document.uploaded_by_user)
else:
print('')
new_document, created = CustomDocument.objects.get_or_create(title=document.title)
new_document.display_text = document.title
new_document.created_at = document.created_at
new_document.uploaded_by_user = document.uploaded_by_user
new_document.file = document.file
new_document.collection = document.collection
new_document.file_hash = document.file_hash
new_document.file_size = document.file_size
new_document.save()
if created:
print(f'Created New Document {new_document}')
else:
print(f'Udated document {document}')

View File

@ -0,0 +1,54 @@
# Generated by Django 3.2.13 on 2022-07-28 08:48
import assignments.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import surveys.models
import taggit.managers
import wagtail.core.blocks
import wagtail.core.fields
import wagtail.core.models.collections
import wagtail.documents.blocks
import wagtail.images.blocks
import wagtail.search.index
import wagtail.snippets.blocks
class Migration(migrations.Migration):
dependencies = [
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
('wagtailcore', '0066_collection_management_permissions'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('books', '0034_alter_contentblock_contents'),
]
operations = [
migrations.AlterField(
model_name='contentblock',
name='contents',
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock()), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock())]))], blank=True, null=True),
),
migrations.CreateModel(
name='CustomDocument',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='title')),
('file', models.FileField(upload_to='documents', verbose_name='file')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
('file_size', models.PositiveIntegerField(editable=False, null=True)),
('file_hash', models.CharField(blank=True, editable=False, max_length=40)),
('display_text', models.CharField(default='', max_length=1024)),
('collection', models.ForeignKey(default=wagtail.core.models.collections.get_root_collection_id, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.collection', verbose_name='collection')),
('tags', taggit.managers.TaggableManager(blank=True, help_text=None, through='taggit.TaggedItem', to='taggit.Tag', verbose_name='tags')),
('uploaded_by_user', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded by user')),
],
options={
'verbose_name': 'document',
'verbose_name_plural': 'documents',
'abstract': False,
},
bases=(wagtail.search.index.Indexed, models.Model),
),
]

View File

@ -4,3 +4,4 @@ from .topic import *
from .chapter import *
from .contentblock import *
from .snapshot import *
from .custom_document import *

View File

@ -4,6 +4,7 @@ from django.db import models
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList, StreamFieldPanel
from wagtail.core.blocks import StreamBlock
from wagtail.core.fields import StreamField
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.images.blocks import ImageChooserBlock
from core.wagtail_utils import get_default_settings
@ -63,7 +64,8 @@ class ContentBlock(StrictHierarchyPage):
('thinglink_block', ThinglinkBlock()),
('subtitle', SubtitleBlock()),
('instruction', InstructionBlock()),
('module_room_slug', ModuleRoomSlugBlock())
('module_room_slug', ModuleRoomSlugBlock()),
('cms_document_block', DocumentChooserBlock())
]
content_list_item = StreamBlock(content_blocks)

View File

@ -0,0 +1,13 @@
from django.db import models
from wagtail.documents.models import Document, AbstractDocument
class CustomDocument(AbstractDocument):
# Custom field example:
display_text = models.CharField(
max_length=1024, default='')
admin_form_fields = Document.admin_form_fields + (
'display_text',
)

View File

@ -1,6 +1,3 @@
import logging
from datetime import datetime
from django.db import models
from django.utils import timezone
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList
@ -52,7 +49,9 @@ class Module(StrictHierarchyPage):
parent_page_types = ['books.Topic']
subpage_types = ['books.Chapter']
#todo: isn't this a duplicate definition?
# todo: isn't this a duplicate definition?
def get_child_ids(self):
return self.get_children().values_list('id', flat=True)
@ -93,6 +92,8 @@ class Module(StrictHierarchyPage):
for objective_group in objective_groups:
objective_group.sync_visibility(school_class_template, school_class_to_sync)
def get_admin_display_title(self):
return f"{self.meta_title} - {self.title}"
class RecentModule(models.Model):

View File

@ -30,7 +30,6 @@ class Topic(StrictHierarchyPage):
FieldPanel('description'),
]
edit_handler = TabbedInterface([
ObjectList(content_panels, heading='Content'),
get_default_settings()
@ -40,3 +39,7 @@ class Topic(StrictHierarchyPage):
parent_page_types = ['books.Book']
subpage_types = ['books.Module']
def get_admin_display_title(self):
return f"" \
f"{self.get_verbose_name()}- {self.title}"

View File

@ -12,7 +12,7 @@ class InputTypes(graphene.Enum):
video_block = 'video_block'
document_block = 'document_block'
content_list_item = 'content_list_item'
subtitle= 'subtitle'
subtitle = 'subtitle'
class ContentElementValueInput(InputObjectType):

View File

@ -40,7 +40,7 @@ ALLOWED_BLOCKS = (
'assignment',
'document_block',
'content_list_item',
'subtitle'
'subtitle',
)

View File

@ -0,0 +1,29 @@
from django.test import TestCase
from wagtail.documents.models import Document
from books.migrate_document_model import migrate_documents_to_custom_document_model
from books.models.custom_document import CustomDocument
TITLE = 'T9 M2 A2: Quellencheck'
class NewContentBlockMutationTest(TestCase):
def setUp(self):
old_document, created = Document.objects.get_or_create(title=TITLE, file='whatever_is_green.pdf')
migrate_documents_to_custom_document_model()
def test_migrate_creates_new_document(self):
self.assertEqual(Document.objects.all().count(), 1)
self.assertEqual(Document.objects.filter(title=TITLE).count(), 1)
self.assertEqual(CustomDocument.objects.filter(title=TITLE).count(), 1)
def test_migrate_display_title_migration(self):
new_document = CustomDocument.objects.get(title=TITLE)
self.assertEqual(new_document.display_text, TITLE)
def test_migration_is_indempodent(self):
migrate_documents_to_custom_document_model()
migrate_documents_to_custom_document_model()
self.assertEqual(Document.objects.all().count(), 1)
self.assertEqual(Document.objects.filter(title=TITLE).count(), 1)
self.assertEqual(CustomDocument.objects.filter(title=TITLE).count(), 1)

View File

@ -0,0 +1,36 @@
from django.core.management import BaseCommand
from core.factories import UserFactory
from users.services import create_users, create_student
from .data.user_data import user_data
from users.models import User
class Command(BaseCommand):
def handle(self, *args, **options):
UserFactory(
username='test',
is_staff=True,
is_superuser=True,
first_name='Nicol',
last_name='Bolas',
onboarding_visited=True
)
create_users(user_data)
# create student without class
create_student(
username='hansli',
first_name='Hansli',
last_name='Alleini'
)
users = User.objects.all()
for usr in users:
print(usr.email)
usr.set_password('test')
usr.save()

View File

@ -367,6 +367,8 @@ WAGTAILSEARCH_BACKENDS = {
'BACKEND': 'wagtail.search.backends.database',
}
}
WAGTAILDOCS_DOCUMENT_MODEL = 'books.CustomDocument'
GRAPHQL_QUERIES_DIR = os.path.join(BASE_DIR, '..', 'client', 'src', 'graphql', 'gql', 'queries')
GRAPHQL_MUTATIONS_DIR = os.path.join(GRAPHQL_QUERIES_DIR, '../mutations')

View File

@ -0,0 +1,123 @@
{# This template is overwritten to create a custom cms ui for the model "chapter" to improve navigation experience.#}
{# See MS-538#}
{% load i18n %}
{% load l10n %}
{% load wagtailadmin_tags %}
<table class="listing {% if full_width %}full-width{% endif %} {% block table_classname %}{% endblock %}">
{% if show_ordering_column or show_bulk_actions %}
<col width="10px"/>
{% endif %}
<col/>
{% if show_parent %}
<col/>
{% endif %}
<col width="12%"/>
<col width="12%"/>
<col width="12%"/>
<col width="10%"/>
<thead>
{% block pre_parent_page_headers %}
{% endblock %}
{% if parent_page %}
{% page_permissions parent_page as parent_page_perms %}
<tr class="index {% if not parent_page.live %} unpublished{% endif %}
{% block parent_page_row_classname %}{% endblock %}">
<td class="title"{% if show_ordering_column or show_bulk_actions %} colspan="2"{% endif %}>
{% block parent_page_title %}
{% endblock %}
</td>
<td class="updated" valign="bottom">{% if parent_page.latest_revision_created_at %}
<div class="human-readable-date"
title="{{ parent_page.latest_revision_created_at|date:"DATETIME_FORMAT" }}">
{% blocktrans with time_period=parent_page.latest_revision_created_at|timesince %}{{ time_period }}
ago{% endblocktrans %}</div>{% endif %}</td>
<td class="type" valign="bottom">
{% if not parent_page.is_root %}
{{ parent_page.content_type.model_class.get_verbose_name }}
{% endif %}
</td>
<td class="status" valign="bottom">
{% if not parent_page.is_root %}
{% include "wagtailadmin/shared/page_status_tag.html" with page=parent_page %}
{% endif %}
</td>
<td></td>
</tr>
{% endif %}
{% block post_parent_page_headers %}
{% endblock %}
</thead>
<tbody>
{% if pages %}
{% trans "Select page" as checkbox_aria_label %}
{% for page in pages %}
{% page_permissions page as page_perms %}
<tr {% if ordering == "ord" %}id="page_{{ page.id|unlocalize }}"
data-page-title="{{ page.get_admin_display_title }}"{% endif %}
class="{% if not page.live %}unpublished{% endif %} {% block page_row_classname %}{% endblock %}">
{% if show_ordering_column %}
<td class="ord">{% if orderable and ordering == "ord" %}
<div class="handle icon icon-grip text-replace">{% trans 'Drag' %}</div>{% endif %}</td>
{% elif show_bulk_actions %}
{% include "wagtailadmin/bulk_actions/listing_checkbox_cell.html" with obj_type="page" obj=page aria_labelledby_prefix="page_" aria_labelledby=page.pk|unlocalize aria_labelledby_suffix="_title" %}
{% endif %}
<td id="page_{{ page.pk|unlocalize }}_title" class="title" valign="top" data-listing-page-title>
{% block page_title %}
{% endblock %}
{% if page.content_type.model == 'chapter' %}
<div style="margin-top:10px; padding-left: 30px">
<ul>
{% for c in page.get_children %}
{% if not c.specific.user_created and not c.specific.contentblocksnapshot %}
<li>
{% if page_perms.can_edit %}
<a href="{% url 'wagtailadmin_pages:edit' c.id %}"
title="{% trans 'Edit this page' %}"> {{ c.get_admin_display_title }}
</a>
{% else %}
{{ c.get_admin_display_title }}
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
</td>
{% if show_parent %}
<td class="parent" valign="top">
{% block page_parent_page_title %}
{% with page.get_parent as parent %}
{% if parent %}
<a href="{% url 'wagtailadmin_explore' parent.id %}">{{ parent.specific_deferred.get_admin_display_title }}</a>
{% endif %}
{% endwith %}
{% endblock %}
</td>
{% endif %}
<td class="updated" valign="top">{% if page.latest_revision_created_at %}
<div class="human-readable-date"
title="{{ page.latest_revision_created_at|date:"DATETIME_FORMAT" }}">
{% blocktrans with time_period=page.latest_revision_created_at|timesince %}{{ time_period }}
ago{% endblocktrans %}</div>{% endif %}</td>
<td class="type" valign="top">{{ page.content_type.model_class.get_verbose_name }}</td>
<td class="status" valign="top">
{% include "wagtailadmin/shared/page_status_tag.html" with page=page %}
</td>
{% block page_navigation %}
{% endblock %}
</tr>
{% endfor %}
{% else %}
{% block no_results %}{% endblock %}
{% endif %}
</tbody>
</table>

View File

@ -6,10 +6,12 @@ from django.urls import re_path
from django.views.generic import RedirectView
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.core import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls
from wagtailautocomplete.urls.admin import urlpatterns as autocomplete_admin_urls
from core import views
from core.views import override_wagtailadmin_explore_default_ordering
urlpatterns = [
# django admin
@ -18,7 +20,9 @@ urlpatterns = [
# 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)),
# graphql backend
url(r'^api/', include('api.urls', namespace="api")),

View File

@ -1,11 +1,11 @@
import requests
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http.response import HttpResponse
from django.http.response import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic import TemplateView
from graphene_django.views import GraphQLView
from wagtail.admin.views.pages.listing import index as wagtailadmin_explore
class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
@ -24,3 +24,14 @@ def home(request):
print('Can not connect to dev server at http://localhost:8080:', e)
return render(request, 'index.html', {})
def override_wagtailadmin_explore_default_ordering(request, parent_page_id):
"""
Wrap Wagtail's explore view to change the default ordering
"""
if request.method == 'GET' and 'ordering' not in request.GET:
# Display reordering handles by default for children of all Page types.
return HttpResponseRedirect(request.path_info + '?ordering=ord')
return wagtailadmin_explore(request, parent_page_id=parent_page_id)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
# Generated by Django 3.2.13 on 2022-07-28 08:48
from django.db import migrations, models
import django.db.models.deletion
import wagtail.core.blocks
import wagtail.core.fields
class Migration(migrations.Migration):
dependencies = [
('rooms', '0011_alter_roomentry_contents'),
]
operations = [
migrations.AlterField(
model_name='comment',
name='room_entry',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='rooms.roomentry'),
),
migrations.AlterField(
model_name='roomentry',
name='contents',
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True),
),
]

View File

@ -2,15 +2,21 @@ from django.contrib.auth import get_user_model
from django.db import models
from django.db.models import JSONField
from wagtail.snippets.models import register_snippet
from wagtail.search import index
@register_snippet
class Survey(models.Model):
class Survey(models.Model, index.Indexed):
title = models.CharField(max_length=255)
module = models.ForeignKey('books.Module', related_name='surveys', on_delete=models.CASCADE, null=True,
blank=True)
data = JSONField()
search_fields = [
index.SearchField('title', partial_match=True),
index.SearchField('module__meta_title', partial_match=True),
]
def __str__(self):
return self.title

View File

@ -0,0 +1,14 @@
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from .models import Survey
class SurveyAdmin(ModelAdmin):
model = Survey
menu_label = 'Surveys'
list_display = ('title', 'module')
search_fields = ('title', 'module__meta_title')
menu_icon = 'help'
modeladmin_register(SurveyAdmin)