diff --git a/server/books/management/commands/migrate_objectives_to_content.py b/server/books/management/commands/migrate_objectives_to_content.py index 9f5df387..48211b5f 100644 --- a/server/books/management/commands/migrate_objectives_to_content.py +++ b/server/books/management/commands/migrate_objectives_to_content.py @@ -3,6 +3,7 @@ from logging import getLogger from django.core.management import BaseCommand from django.core.exceptions import ValidationError +from django.db import models from books.models import Chapter, ObjectiveGroupSnapshot, Snapshot, ContentBlockSnapshot, ChapterSnapshot from books.models import ContentBlock @@ -11,6 +12,7 @@ from objectives.models import ObjectiveSnapshot, Objective, ObjectiveGroup logger = getLogger(__name__) + class Command(BaseCommand): def handle(self, *args, **options): ContentBlock.objects.filter(title__startswith="TESTOBJECTIVE").delete() @@ -21,110 +23,131 @@ class Command(BaseCommand): migrate_objectives_to_content() + def migrate_objectives_to_content(): - created_content_blocks = 0 + created_content_blocks = 0 - failed_modules = [] + failed_modules = [] - # This dict stores all content blocks that have been created for a set of objectives - # In this way we can reuse content blocks for the same set of objectives - created_default_content_blocks = {} + # This dict stores all content blocks that have been created for a set of objectives + # In this way we can reuse content blocks for the same set of objectives + created_default_content_blocks = {} - for module in Module.objects.all(): - try: - chapter = create_chapter_from_objective_group(module) + for module in Module.objects.all(): + try: + chapter = create_chapter_from_objective_group(module) - for objective_group in module.objective_groups.all().order_by('title'): - default_objectives = list(objective_group.objectives.filter(owner__isnull=True, ) - .exclude(objectivesnapshot__isnull=False).order_by('order')) + for objective_group in get_objectives_groups_in_specific_order(module): + default_objectives = list(objective_group.objectives.filter(owner__isnull=True, ) + .exclude(objectivesnapshot__isnull=False).order_by('order')) - default_objectives_ids = tuple(objective.id for objective in default_objectives) + default_objectives_ids = tuple(objective.id for objective in default_objectives) - # Create "Verlagsinhalte" content block if it does not exist yet - if default_objectives_ids not in created_default_content_blocks: - default_content_block = create_default_content(objective_group, chapter) - created_default_content_blocks[default_objectives_ids] = default_content_block - else: - default_content_block = created_default_content_blocks[default_objectives_ids] + # Create "Verlagsinhalte" content block if it does not exist yet + if default_objectives_ids not in created_default_content_blocks: + default_content_block = create_default_content(objective_group, chapter) + created_default_content_blocks[default_objectives_ids] = default_content_block + else: + default_content_block = created_default_content_blocks[default_objectives_ids] - custom_objectives_by_owner = get_objectives_by_owner(objective_group) + custom_objectives_by_owner = get_objectives_by_owner(objective_group) - if default_objectives or custom_objectives_by_owner: - contentblocks_by_merged_objectives_ids = {} + if default_objectives or custom_objectives_by_owner: + contentblocks_by_merged_objectives_ids = {} - # cor custom objectives iterate over owners, - # - one ownsers custom objectives must not be changed by another owner - # - visibility is set per class - for owner, owner_objectives in custom_objectives_by_owner.items(): - print(f"Owner: {owner}") - print(f" Objectives: ") + # cor custom objectives iterate over owners, + # - one ownsers custom objectives must not be changed by another owner + # - visibility is set per class + for owner, owner_objectives in custom_objectives_by_owner.items(): + print(f"Owner: {owner}") + print(f" Objectives: ") - visible_default_objectives_by_class = filter_visible_objectives_by_class(default_objectives, owner) + visible_default_objectives_by_class = filter_visible_objectives_by_class(default_objectives, + owner) - for school_class, default_objectives_for_class in visible_default_objectives_by_class.items(): - custom_content_block = None + for school_class, default_objectives_for_class in visible_default_objectives_by_class.items(): + custom_content_block = None - print(f" School class: {school_class}") - # merge "Verlagsinhalte" and "benutzerdefinierte Inhalte" - visible_owner_objectives = [objective for objective in owner_objectives if not objective.is_hidden_for_class(school_class)] + print(f" School class: {school_class}") + # merge "Verlagsinhalte" and "benutzerdefinierte Inhalte" + visible_owner_objectives = [objective for objective in owner_objectives if + not objective.is_hidden_for_class(school_class)] - merged_objectives = default_objectives_for_class + visible_owner_objectives - merged_objectives_ids = tuple(objective.id for objective in merged_objectives) - is_default_content = merged_objectives_ids == default_objectives_ids + merged_objectives = default_objectives_for_class + visible_owner_objectives + merged_objectives_ids = tuple(objective.id for objective in merged_objectives) + is_default_content = merged_objectives_ids == default_objectives_ids - if is_default_content: - print(f" Objective: Reuse default content block") - # custom_content_block = default_content_block + if is_default_content: + print(f" Objective: Reuse default content block") + # custom_content_block = default_content_block - # Create content block if that set of objectives has not been created yet - if merged_objectives_ids not in contentblocks_by_merged_objectives_ids and not is_default_content: - for objective in merged_objectives: - print(f" Objective: {objective} {objective.owner}") + # Create content block if that set of objectives has not been created yet + if merged_objectives_ids not in contentblocks_by_merged_objectives_ids and not is_default_content: + for objective in merged_objectives: + print(f" Objective: {objective} {objective.owner}") - if merged_objectives_ids: - custom_content_block = create_content_block_from_objective(objective_group, - chapter, - owner=owner, - ) - contentblocks_by_merged_objectives_ids[ - merged_objectives_ids] = custom_content_block - create_text_in_content_block(merged_objectives, custom_content_block) - created_content_blocks += 1 + if merged_objectives_ids: + custom_content_block = create_content_block_from_objective(objective_group, + chapter, + owner=owner, + ) + contentblocks_by_merged_objectives_ids[ + merged_objectives_ids] = custom_content_block + create_text_in_content_block(merged_objectives, custom_content_block) + created_content_blocks += 1 + else: + if not is_default_content: + print(f" Objective: Reuse content block") + custom_content_block = contentblocks_by_merged_objectives_ids[ + merged_objectives_ids] else: - if not is_default_content: - print(f" Objective: Reuse content block") - custom_content_block = contentblocks_by_merged_objectives_ids[ - merged_objectives_ids] - else: - print(f" Objective: Reuse default content block") + print(f" Objective: Reuse default content block") - # set visibility - # hide default objectives if custom objectives exist - if custom_content_block: - default_content_block.hidden_for.add(school_class) - default_content_block.save_revision().publish() - default_content_block.save() + # set visibility + # hide default objectives if custom objectives exist + if custom_content_block: + default_content_block.hidden_for.add(school_class) + default_content_block.save_revision().publish() + default_content_block.save() - custom_content_block.visible_for.add(school_class) - custom_content_block.save_revision().publish() - custom_content_block.save() + custom_content_block.visible_for.add(school_class) + custom_content_block.save_revision().publish() + custom_content_block.save() - if objective_group.hidden_for.filter(id=school_class.id).exists(): - default_content_block.hidden_for.add(school_class) - default_content_block.save_revision().publish() - default_content_block.save() + if objective_group.hidden_for.filter(id=school_class.id).exists(): + default_content_block.hidden_for.add(school_class) + default_content_block.save_revision().publish() + default_content_block.save() - except ValidationError as e: - print(f"Error with module {module}") - logger.error(e) - failed_modules.append(module) + except ValidationError as e: + print(f"Error with module {module}") + logger.error(e) + failed_modules.append(module) - print(f"Created {created_content_blocks} content blocks") - print(f"Failed modules: {len(failed_modules)}") + print(f"Created {created_content_blocks} content blocks") + print(f"Failed modules: {len(failed_modules)}") - for module in failed_modules: - print(f"Faile module: {module}") + for module in failed_modules: + print(f"Faile module: {module}") + + +def get_objectives_groups_in_specific_order(module): + # Create a specific order for the objective groups + # https://stackoverflow.com/questions/5966462/sort-queryset-by-values-in-list + # https://docs.djangoproject.com/en/5.0/ref/models/conditional-expressions/ + order_of_objective_groups = ["Sprache & Kommunikation", "Gesellschaft", "Übergeordnete Lernziele"] + _whens = [] + for sort_index, value in enumerate(order_of_objective_groups): + _whens.append( + models.When(title=value, then=sort_index) + ) + + qs = module.objective_groups.all().annotate(_sort_index=models.Case(*_whens, + output_field=models.IntegerField() + ) + ).order_by('_sort_index') + return qs def create_default_content(objective_group, chapter): @@ -156,7 +179,8 @@ def filter_visible_objectives_by_class(objectives, user): def get_objectives_by_owner(objective_group, exclude_snapshots=True): - custom_objectives = objective_group.objectives.filter(owner__isnull=False, objectivesnapshot__isnull=True).order_by('order') + custom_objectives = objective_group.objectives.filter(owner__isnull=False, objectivesnapshot__isnull=True).order_by( + 'order') custom_objectives_by_owner = {} for objective in custom_objectives: @@ -233,15 +257,16 @@ def create_text_in_content_block(objectives, content_block, get_or_create=False) if get_or_create: content_block_qs = ContentBlock.objects.filter(title=content_block.title, - owner=content_block.owner, - user_created=content_block.user_created, - contents=content_block.contents) + owner=content_block.owner, + user_created=content_block.user_created, + contents=content_block.contents) if content_block_qs.exists(): content_block = content_block_qs.first() content_block.save_revision().publish() return content_block + def create_content_block_contents(objectives): objectives = list(objectives) objective_li = [f"