import wagtail.admin.views.pages.ordering from django.db.models import ProtectedError from django.shortcuts import redirect from wagtail.admin import messages import wagtail.admin.rich_text.editors.draftail.features as draftail_features from wagtail.admin.rich_text.converters.html_to_contentstate import ( InlineStyleElementHandler, ) from wagtail import hooks from wagtail.admin.utils import get_valid_next_url_from_request from basicknowledge.models import BasicKnowledge from books.models import ContentBlockSnapshot from books.models.chapter import Chapter from books.models.contentblock import ContentBlock from core.logger import get_logger from django.conf import settings from .wagtail_patch import set_page_position logger = get_logger(__name__) theme = settings.THEME if theme == "my-kv": primary = "#2075ff" secondary = "#0fd6a0" elif theme == "my-dha": primary = "#1bab4e" secondary = "#139ee0" elif theme == "my-dhf": primary = "#139ee0" secondary = "#1bab4e" else: primary = "#17A887" secondary = "#078CC6" # Monkey patching wagtail.admin.views.pages.ordering.set_page_position because there is a bug in the original code # github issue: wagtail.admin.views.pages.ordering.set_page_position = set_page_position # 1. Use the register_rich_text_features hook. @hooks.register("register_rich_text_features") def register_brand_feature(features): """ Registering the feature, which uses the `BRAND` Draft.js inline style type, and is stored as HTML with a `` tag. """ feature_name = "brand" type_ = "BRAND" # 2. Configure how Draftail handles the feature in its toolbar. control = { "type": type_, "label": "Auszeichung Primär", "description": "Auszeichung Primär", "style": {"color": primary, "font-weight": "600"}, } # 3. Call register_editor_plugin to register the configuration for Draftail. features.register_editor_plugin( "draftail", feature_name, draftail_features.InlineStyleFeature(control) ) # 4.configure the content transform from the DB to the editor and back. db_conversion = { "from_database_format": { 'span[class="brand"]': InlineStyleElementHandler(type_) }, "to_database_format": {"style_map": {type_: 'span class="brand""'}}, } # 5. Call register_converter_rule to register the content transformation conversion. features.register_converter_rule("contentstate", feature_name, db_conversion) # 6. (optional) Add the feature to the default features list to make it available # on rich text fields that do not specify an explicit 'features' list features.default_features.append(feature_name) @hooks.register("register_rich_text_features") def register_secondary_feature(features): """ Registering the feature, which uses the `SECONDARY` Draft.js inline style type, and is stored as HTML with a `` tag. """ feature_name = "secondary" type_ = "SECONDARY" # 2. Configure how Draftail handles the feature in its toolbar. control = { "type": type_, "label": "Auszeichnung sekundär", "description": "Auszeichnung sekundär", "style": {"color": secondary, "font-weight": "600"}, } # 3. Call register_editor_plugin to register the configuration for Draftail. features.register_editor_plugin( "draftail", feature_name, draftail_features.InlineStyleFeature(control) ) # 4.configure the content transform from the DB to the editor and back. db_conversion = { "from_database_format": { 'span[class="secondary"]': InlineStyleElementHandler(type_) }, "to_database_format": {"style_map": {type_: 'span class="secondary"'}}, } # 5. Call register_converter_rule to register the content transformation conversion. features.register_converter_rule("contentstate", feature_name, db_conversion) # 6. (optional) Add the feature to the default features list to make it available # on rich text fields that do not specify an explicit 'features' list features.default_features.append(feature_name) @hooks.register("construct_explorer_page_queryset") def remove_page_types_from_menu(parent_page, pages, request): # Modify the queryset used to populate the explorer menu, to exclude content that is created by the teachers. # or: Show only content that is created by the content team. return ( pages.not_type(ContentBlockSnapshot) .not_type(BasicKnowledge) .exclude(contentblock__user_created=True) ) @hooks.register("after_copy_page") def after_copy_hook(request, page, new_page): # todo: find every ContentBlock further down in the tree, see if there are any Surveys or Assignments and copy them and reassign them if type(page.specific) == ContentBlock: # logger.debug("It's a content block") content_block: ContentBlock = new_page.specific # logger.debug(f"duplicatin {content_block.title, content_block.pk}") content_block.duplicate_attached_entities() else: # logger.debug(f"It's something else {type(page.specific)}, {ContentBlock}") content_blocks = new_page.specific.get_content_blocks() for content_block in content_blocks: content_block.duplicate_attached_entities() @hooks.register("after_move_page") def after_move_hook(request, page): logger.debug(f"after moving the page {page.title}") if type(page.specific) == ContentBlock: logger.debug("it's a content block") page.specific.reassign_entities() if type(page.specific) == Chapter: logger.debug("it's a chapter") content_blocks = page.specific.get_content_blocks() logger.debug(page.id) logger.debug(page.specific.get_content_blocks()) logger.debug(page.get_children()) for content_block in content_blocks: content_block.reassign_entities() @hooks.register("after_edit_page") def after_edit_hook(request, page): logger.debug(f"After edit page {page.title}, {type(page).__name__}") @hooks.register("after_create_page") def after_create_hook(request, page): # reassign assignment and survey module if type(page.specific) == ContentBlock: content_block = page.specific content_block.reassign_entities() @hooks.register("before_delete_page") def on_page_delete(request, page): if request.method != "POST": return try: next_url = get_valid_next_url_from_request(request) parent_id = page.get_parent().id page.delete() messages.success( request, ("Page '{0}' deleted.").format(page.get_admin_display_title()) ) for fn in hooks.get_hooks("after_delete_page"): result = fn(request, page) if hasattr(result, "status_code"): return result if next_url: return redirect(next_url) return redirect("wagtailadmin_explore", parent_id) except ProtectedError as exc: protected_objects = {} for obj in exc.protected_objects: model_name = obj._meta.verbose_name_plural if model_name in protected_objects: protected_objects[model_name].append(str(obj)) else: protected_objects[model_name] = [str(obj)] dependency_summary = [] for model_name, items in protected_objects.items(): if len(items) == 1: items_summary = ("{0} ({1})").format(model_name, items[0]) else: items_summary = ("{0} ({1} and {2} more...)").format( model_name, items[0], len(items) - 1 ) dependency_summary.append(items_summary) messages.error( request, ("Page '{0}' cannot be deleted while it's used by {1}").format( page.get_admin_display_title(), ", ".join(dependency_summary) ), ) return redirect("wagtailadmin_pages:delete", page.id)