import json from logging import getLogger from django.core.management import BaseCommand from books.management.commands.migrate_objectives_to_content import create_text_in_content_block, \ create_content_block_snapshot_from_objective, \ create_content_block_contents from books.models import Chapter, ObjectiveGroupSnapshot, ContentBlockSnapshot, Snapshot, ChapterSnapshot from books.models import ContentBlock from books.models import Module from objectives.models import Objective, ObjectiveSnapshot, ObjectiveGroup logger = getLogger(__name__) class Command(BaseCommand): def handle(self, *args, **options): """ This command must be run after the migration of objectives to content blocks. Migrate objective snapshots to content blocks - Verlagsinhalte - deafult content blocks are referced in the snapshot by foreign key Man muss unterscheiden zwischen, snapshots die nur Verlagslernziele sichtbar und unsichtbar machen. Und solchen die auch benutzerdefinierte Lernziele sichtbar und unsichtbar machen. Es gibt keine custom objective groups! Es gibt keine hidden custom objective_groups Case1: - 100% Verlagslernziele, 100% Verlagsgruppe, nicht neue content blocks erstellen, nichts hidden... migration muss nichts machen. Case2: - 100% Verlagslernziele, 100% Verlagsgruppe, hidden gruppe, nur verlagsinhalt gruppe verstecken Case3: - Bestende gruppe mit benutzerdefinierten lernzielen, - custom content_block snapshot erstellen. - Einzelne verslagslernziele sind versteckt. - custom content_block snapshot erstellen. --- user created setzen bei custom content snapshot. """ prefix = "SNAP " ContentBlock.objects.filter(title__startswith=prefix).delete() Chapter.objects.filter(title__startswith=prefix).delete() ContentBlockSnapshot.objects.filter(title__startswith=prefix).delete() ChapterSnapshot.objects.filter(chapter__title__startswith=prefix).delete() analyze() migrate_snapshots() def migrate_snapshots(): count = 0 case1_count = 0 case2_count = 0 case3_count = 0 createed_content_blocks = 0 visible_objectives_by_ids = {} snapshot_counter = 0 for module in Module.objects.all(): for snapshot in Snapshot.objects.filter(module=module): group_counter = snapshot.objective_groups.through.objects.filter(objective_group__module=module, snapshot=snapshot).count() print( f"{snapshot_counter} Snapshot id: {snapshot.id} Module: {module.title} {group_counter} groups {snapshot.creator} {snapshot.title}") snapshot_counter += 1 for objective_group_snapshot in snapshot.objective_groups.through.objects.filter( objective_group__module=module, snapshot=snapshot): header = f"{count} {module.title:50} {objective_group_snapshot.objective_group.get_title_display():25} {str(snapshot.creator):40} {objective_group_snapshot.hidden} " count += 1 objective_group = objective_group_snapshot.objective_group hidden_default_objectives = snapshot.hidden_objectives.filter( group=objective_group) visible_custom_objectives = snapshot.custom_objectives.filter(snapshot=snapshot, hidden=False, group=objective_group_snapshot.objective_group) group_is_hidden = objective_group_snapshot.hidden info = f"{hidden_default_objectives.count()} {visible_custom_objectives.count()}" if (not hidden_default_objectives and not visible_custom_objectives and not group_is_hidden): # print(f"{info} Case 1 - skip") case1_count += 1 break if not hidden_default_objectives and not visible_custom_objectives and group_is_hidden: print(header + f"Case 2 - {info} hide default content group") case2_count += 1 content_block = get_content_block_by_objective_group(objective_group_snapshot, module, False, None) snapshot.hidden_content_blocks.add(content_block.id) snapshot.save() if hidden_default_objectives or visible_custom_objectives: print(header + f"Case 3 - {info} create custom content blocks") case3_count += 1 # Verlags Lernziele visible_default_objectives = get_visible_default_objectives(objective_group, module, snapshot) # Benutzerdefinierte Lernziele visible_custom_objectives = list(snapshot.custom_objectives.filter(hidden=False)) visible_objectives = visible_default_objectives + visible_custom_objectives # filter for unique texts in objectives # TODO: I don't know why there are duplicated objectives objectives_by_texts = {} for objective in visible_objectives: if objective.text not in objectives_by_texts: objectives_by_texts[objective.text] = objective visible_objectives = list(objectives_by_texts.values()) if visible_objectives: # make combinations of objectives unique by text, this prevents generation of many duplicated content blocks visible_objectives_hash = hash( [objective.text for objective in visible_objectives].__str__()) visible_objectives_by_ids[visible_objectives_hash] = visible_objectives for objectives in visible_objectives_by_ids.values(): print("") for objective in objectives: print(f" Objective: {objective.group} {objective} owner:{objective.owner}") print("-") print(f" visible_objectives_by_ids: {len(visible_objectives_by_ids.items())}") # create custom content blocks with the objectives created_content_blocks = 0 chapter = module.get_first_child() if "Lernziele" not in chapter.title: raise Exception(f"Chapter does not contain 'Lernziele' first title is {chapter.title}") # Owner des custom blocks festlegen custom_content_block_snapshot = create_content_block_snapshot_from_objective( objective_group, chapter, snapshot, owner=snapshot.creator) # Hide default content block for this objective group, since custom content block is created default_content_block = get_default_content_block(objective_group_snapshot, module) if default_content_block: print(f"Default content block: {default_content_block.title}") snapshot.hidden_content_blocks.add(default_content_block.id) if list(visible_objectives_by_ids.values()): objectives = list(visible_objectives_by_ids.values())[0] create_text_in_content_block(objectives, custom_content_block_snapshot, get_or_create=True) created_content_blocks += 1 snapshot.save() print() print(f"Skipped {case1_count} Case 1") print(f"Hidden default content groups {case2_count} Case 2") print(f"Created new content {case3_count} Case 3") def get_content_block_by_objective_group(objective_group_snapshot, module, user_created: bool, user): # TODO: review qustion, is it necessary to filter for module content_block = ContentBlock.objects.filter( title__contains=objective_group_snapshot.objective_group.get_title_display(), user_created=user_created, owner=user).descendant_of(module) if content_block.count() > 1: return content_block.first() return content_block.first() def get_default_content_block(objective_group_snapshot, module): default_objectives = Objective.objects.filter(group=objective_group_snapshot.objective_group, group__module=module, owner__isnull=True, objectivesnapshot__isnull=True) default_content_block_contents = create_content_block_contents(default_objectives) contents = json.loads(default_content_block_contents) contents[0].get("value").get("text") chapter = Chapter.objects.filter(title__contains="Lernziele").descendant_of(module) text_contents = contents[0].get("value").get("text") group_title = objective_group_snapshot.objective_group.get_title_display() content_blocks = ContentBlock.objects.filter(user_created=False).descendant_of(chapter.first()) for content_block in content_blocks: print(content_block.title, group_title) if group_title in content_block.title: return content_block if not content_block.exists(): raise Exception("Content block does not exist ") def get_visible_default_objectives(objective_group, module, snapshot): default_objectives = Objective.objects.filter(group=objective_group, group__module=module, owner__isnull=True, objectivesnapshot__isnull=True) hidden_default_objectives = snapshot.hidden_objectives.filter(group=objective_group) visible_default_objectives = [objective for objective in default_objectives if objective.id not in hidden_default_objectives.values_list("id", flat=True)] return visible_default_objectives def analyze(): print(f""" OjectiveGroups: {ObjectiveGroup.objects.count()} Objectives: {Objective.objects.count()} ObjectiveGroupSnapshots: {ObjectiveGroupSnapshot.objects.count()} ObjectivesSnapshots: {ObjectiveSnapshot.objects.count()} ObjectiveGroups: {ObjectiveGroup.objects.filter(objectivegroupsnapshot__isnull=True).count()} Objectives: {Objective.objects.filter(objectivesnapshot__isnull=True).count()} Snapshot: {Snapshot.objects.count()} """)