From d92f6049aeb220aac624eb70d7beb5cc2cc33890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <tomas@imaniti.org> Date: Tue, 4 Jun 2024 13:48:50 +0200 Subject: [PATCH] WIP - migrate programs --- .../migrations/0218_auto_20240601_1530.py | 522 +++++++++++------- district/models.py | 2 +- .../0037_alter_electionshomepage_content.py | 21 + .../0094_alter_mainprogrampage_program.py | 21 + 4 files changed, 366 insertions(+), 200 deletions(-) create mode 100644 elections/migrations/0037_alter_electionshomepage_content.py create mode 100644 main/migrations/0094_alter_mainprogrampage_program.py diff --git a/district/migrations/0218_auto_20240601_1530.py b/district/migrations/0218_auto_20240601_1530.py index eccb9122..2ae930bc 100644 --- a/district/migrations/0218_auto_20240601_1530.py +++ b/district/migrations/0218_auto_20240601_1530.py @@ -1,9 +1,10 @@ # Generated by Django 5.0.4 on 2024-06-01 13:30 from django.db import migrations, transaction +import wagtail -from district.blocks import ProgramGroupWithCandidatesBlock -from shared.blocks import SocialLinkBlock +from district.blocks import ProgramGroupWithCandidatesBlock, CandidateListBlock, CandidateBlock, CandidateSecondaryListBlock, SecondaryCandidateBlock, ProgramGroupBlockPopout +from shared.blocks import SocialLinkBlock, ProgramBlockPopout def migrate_programs(apps, schema_editor): @@ -66,28 +67,45 @@ def migrate_programs(apps, schema_editor): ) for home_page in DistrictHomePage.objects.all(): - election_data = { - # Title - "title": "", # Done - "order": 0, - # Program lists - "program_points": [], - "post_election_strategies": [], - # Candidates - "candidate_list_number": "", - "candidate_list_title": "", - "candidate_pages": [], - "candidate_blocks": [], # Page creation done - "combined_candidates": [], - "primary_candidate_count": 0, - # Program - "program_title": "", - "program_is_inline": False, - "program_content_before": "", # Done - # Misc. - "funding_info": "", - } + # Create a new program page, even if this DistrictHomePage will + # end up having no programs. + max_path_page = ( + Page.objects.filter( + path__startswith=home_page.path, depth=home_page.depth + 1 + ) + .order_by("-path") + .first() + ) + + if max_path_page: + max_path = max_path_page.path + next_path_suffix = ( + int(max_path[-4:], 36) + 1 + ) # Base-36 to handle alphanumeric paths + next_path = ( + max_path[:-4] + f"{next_path_suffix:04X}" + ) # Convert back to base-36 + else: + next_path = home_page.path + "0001" + + # Create the new program page + with transaction.atomic(): + new_program_page = DistrictNewProgramPage( + title="Programy", + slug="programy", # Make sure the slug is unique among siblings + path=next_path, + depth=home_page.depth + 1, + numchild=0, + content_type_id=new_program_page_content_type.id, + locale_id=default_locale.id, + ) + new_program_page.save() + + # Update numchild on the home page + home_page.numchild = home_page.numchild + 1 + home_page.save(update_fields=["numchild"]) + # Iterate over all child DistrictElectionRootPage instances for election_root_page in get_children_of_type( DistrictElectionRootPage, home_page, root_page_content_type @@ -100,39 +118,79 @@ def migrate_programs(apps, schema_editor): ) for campaign_page in campaign_pages: - election_data["title"] = ( + # Data for a single program + + program_data = { + # Title + "title": "", # Done + "order": 0, + + # Post-election + "post_election_strategies": [], + + # Candidates + "candidate_list_number": "", + "candidate_list_title": "", # Done + "candidate_pages": [], # Done + "candidate_blocks": [], # Done + "combined_candidates": [], # Done + "primary_candidate_count": 0, # Done + + # Program + "program_title": "", + "program_points": [], + "program_is_inline": False, + "program_content_before": "", # Done + + # Misc. + "funding_info": "", + } + + program_data["title"] = ( election_root_page.title if election_root_page.title else campaign_page.title ) - election_data["order"] = campaign_page.order + program_data["order"] = campaign_page.order - election_data["candidate_list_number"] = campaign_page.number - election_data[ + program_data["candidate_list_number"] = campaign_page.number + program_data[ "candidate_list_title" ] = campaign_page.candidate_list_title - election_data["program_title"] = campaign_page.program_point_list_title - election_data[ + program_data["program_title"] = ( + campaign_page.program_point_list_title + if campaign_page.program_point_list_title + else campaign_page.title + ) + + program_data[ "program_is_inline" ] = campaign_page.show_program_points_inline - election_data["funding_info"] = campaign_page.campaign_funding_info + program_data["funding_info"] = campaign_page.campaign_funding_info position = 0 + # Parse candidates from blocks for candidate_list_block in campaign_page.candidates.get_prep_value(): candidate_list = candidate_list_block["value"] - election_data["primary_candidate_count"] = candidate_list[ + program_data["primary_candidate_count"] = candidate_list[ "candidate_list_big_count" ] for candidate in candidate_list["candidate_list"]: - position = position + 1 - if candidate["type"] == "person_page": + if DistrictPersonPage.objects.filter( + id=candidate["value"] + ).first() is None: + # We have nothing to do here, this page ID is either unfilled or points to a missing page + continue + + position = position + 1 + candidate_data = { "position": position, "page": DistrictPersonPage.objects.filter( @@ -140,32 +198,38 @@ def migrate_programs(apps, schema_editor): ).first(), } - election_data["candidate_pages"].append(candidate_data) - election_data["combined_candidates"].append(candidate_data) + program_data["candidate_pages"].append(candidate_data) + program_data["combined_candidates"].append(candidate_data) continue - if candidate["type"] == "person_blocks": - election_data["candidate_blocks"].append( + elif candidate["type"] == "person_blocks": + position = position + 1 + + program_data["candidate_blocks"].append( {"position": position, "data": candidate["value"]} ) + # Parse program points program_pages = get_children_of_type( DistrictElectionProgramPage, - election_root_page, + campaign_page, program_page_content_type, ) for program_page in program_pages: - election_data["program_points"].append( + program_data["program_points"].append( { - "guarantor_page": program_page.guarantor, - "image": program_page.image, - "perex": program_page.perex, - "funding_info": program_page.campaign_funding_info, + "title": program_page.title, # Done + "guarantor_page": program_page.guarantor, # Done + "image": program_page.image, # Ignoring + "perex": program_page.perex, # Done + "content": program_page.content, # Done + "funding_info": program_page.campaign_funding_info, # TODO: Ignoring? } ) + # Parse post-election strategies post_election_strategy_pages = get_children_of_type( DistrictPostElectionStrategyPage, election_root_page, @@ -173,184 +237,232 @@ def migrate_programs(apps, schema_editor): ) for post_election_strategy_page in post_election_strategy_pages: - election_data["post_election_strategies"].append( + program_data["post_election_strategies"].append( { "perex": post_election_strategy_page.perex, } ) - if ( - len(election_data["candidate_pages"]) == 0 - and len(election_data["candidate_blocks"]) == 0 - and len(election_data["program_points"]) == 0 - ): - continue # Do nothing for these + # If there's no program data, skip this iteration. + if ( + len(program_data["candidate_pages"]) == 0 + and len(program_data["candidate_blocks"]) == 0 + and len(program_data["program_points"]) == 0 + ): + continue # Do nothing for these - parent_people_page = get_children_of_type( - DistrictPeoplePage, home_page, people_page_content_type - ) - - parent_people_page = parent_people_page.first() - - # Create corresponding pages for the candidate blocks - for candidate_block in election_data["candidate_blocks"]: - if parent_people_page is None: - break # We can't do anything here - - social_links = [] - - if candidate_block["data"]["facebook_url"]: - social_links.append( - SocialLinkBlock().to_python( - { - "icon": "ico--facebook", - "text": "Facebook", - "link": candidate_block["data"]["facebook_url"], - } - ) + parent_people_page = get_children_of_type( + DistrictPeoplePage, home_page, people_page_content_type ) - if candidate_block["data"]["instagram_url"]: - social_links.append( - SocialLinkBlock().to_python( - { - "icon": "ico--instagram", - "text": "Instagram", - "link": candidate_block["data"]["instagram_url"], - } - ) - ) + parent_people_page = parent_people_page.first() - if candidate_block["data"]["twitter_url"]: - social_links.append( - SocialLinkBlock().to_python( - { - "icon": "ico--twitter", - "text": "Twitter", - "link": candidate_block["data"]["twitter_url"], - } - ) - ) + # Create corresponding pages for candidate blocks with no pages + for candidate_block in program_data["candidate_blocks"]: + if parent_people_page is None: + break # We can't do anything here - if candidate_block["data"]["youtube_url"]: - social_links.append( - SocialLinkBlock().to_python( - { - "icon": "ico--youtube", - "text": "YouTube", - "link": candidate_block["data"]["youtube_url"], - } + social_links = [] + + if candidate_block["data"]["facebook_url"]: + social_links.append( + SocialLinkBlock().to_python( + { + "icon": "ico--facebook", + "text": "Facebook", + "link": candidate_block["data"]["facebook_url"], + } + ) + ) + + if candidate_block["data"]["instagram_url"]: + social_links.append( + SocialLinkBlock().to_python( + { + "icon": "ico--instagram", + "text": "Instagram", + "link": candidate_block["data"]["instagram_url"], + } + ) + ) + + if candidate_block["data"]["twitter_url"]: + social_links.append( + SocialLinkBlock().to_python( + { + "icon": "ico--twitter", + "text": "Twitter", + "link": candidate_block["data"]["twitter_url"], + } + ) + ) + + if candidate_block["data"]["youtube_url"]: + social_links.append( + SocialLinkBlock().to_python( + { + "icon": "ico--youtube", + "text": "YouTube", + "link": candidate_block["data"]["youtube_url"], + } + ) + ) + + if candidate_block["data"]["flickr_url"]: + social_links.append( + SocialLinkBlock().to_python( + { + "icon": "ico--flickr", + "text": "Flickr", + "link": candidate_block["data"]["flickr_url"], + } + ) + ) + + max_path_page = ( + Page.objects.filter( + path__startswith=people_page.path, + depth=parent_people_page.depth + 1, + ) + .order_by("-path") + .first() ) - ) - if candidate_block["data"]["flickr_url"]: - social_links.append( - SocialLinkBlock().to_python( + if max_path_page: + max_path = max_path_page.path + next_path_suffix = ( + int(max_path[-4:], 36) + 1 + ) # Base-36 to handle alphanumeric paths + next_path = ( + max_path[:-4] + f"{next_path_suffix:04X}" + ) # Convert back to base-36 + else: + next_path = parent_people_page.path + "0001" + + with transaction.atomic(): + candidate_page = DistrictPersonPage( + title=candidate_block["data"]["title"], + job=candidate_block["data"]["job"], + profile_image_id=candidate_block["data"]["profile_photo"], + email=candidate_block["data"]["email"], + city=candidate_block["data"]["city"], + age=candidate_block["data"]["age"], + is_pirate=candidate_block["data"]["is_pirate"], + other_party=candidate_block["data"]["other_party"], + other_party_logo_id=candidate_block["data"]["other_party_logo"], + social_links=social_links, + content_type_id=people_page_content_type.id, + locale_id=default_locale.id, + ) + + candidate_page.numchild = candidate_page.numchild + 1 + candidate_page.save(update_fields=["numchild"]) + + program_data["combined_candidates"].append( { - "icon": "ico--flickr", - "text": "Flickr", - "link": candidate_block["data"]["flickr_url"], + "position": candidate_block["position"], + "page": candidate_page, } ) - ) - - max_path_page = ( - Page.objects.filter( - path__startswith=people_page.path, - depth=parent_people_page.depth + 1, - ) - .order_by("-path") - .first() - ) - if max_path_page: - max_path = max_path_page.path - next_path_suffix = ( - int(max_path[-4:], 36) + 1 - ) # Base-36 to handle alphanumeric paths - next_path = ( - max_path[:-4] + f"{next_path_suffix:04X}" - ) # Convert back to base-36 - else: - next_path = parent_people_page.path + "0001" - - with transaction.atomic(): - candidate_page = DistrictPersonPage( - title=candidate_block["data"]["title"], - job=candidate_block["data"]["job"], - profile_image_id=candidate_block["data"]["profile_photo"], - email=candidate_block["data"]["email"], - city=candidate_block["data"]["city"], - age=candidate_block["data"]["age"], - is_pirate=candidate_block["data"]["is_pirate"], - other_party=candidate_block["data"]["other_party"], - other_party_logo_id=candidate_block["data"]["other_party_logo"], - social_links=social_links, - content_type_id=people_page_content_type.id, - locale_id=default_locale.id, + # Sort candidates + program_data["combined_candidates"] = sorted( + program_data["combined_candidates"], + key=lambda value: value["position"], ) - candidate_page.numchild = candidate_page.numchild + 1 - candidate_page.save(update_fields=["numchild"]) - - election_data["combined_candidates"].append( - { - "position": candidate_block["position"], - "data": candidate_page, + # Create candidate blocks + primary_candidates = [] + secondary_candidates = [] + + for position, candidate in enumerate(program_data["combined_candidates"]): + if position <= program_data["primary_candidate_count"]: + primary_candidates.append({ # CandidateBlock value for CandidateListBlock + "page": candidate["page"].id, + "description": ( + candidate["page"].perex + if len(candidate["page"].perex) > 32 + else ( + candidate["page"].job + if candidate["page"].job + else candidate["page"].position + ) + ), + "image": ( + candidate["page"].profile_image.id + # Not sure why there is a need to check for the second condition. + # But, without it, the migration crashes on some images. + if candidate["page"].profile_image is not None + else 0 + ) + }) + else: + secondary_candidates.append({ # SecondaryCandidateBlock value for CandidateSecondaryListBlock + "number": candidate["position"], + "page": candidate["page"].id, + }) + + primary_candidates_block = { + # Acts as CandidateListBlock + "candidates": primary_candidates, } - ) - - max_path_page = ( - Page.objects.filter( - path__startswith=home_page.path, depth=home_page.depth + 1 - ) - .order_by("-path") - .first() - ) - - if max_path_page: - max_path = max_path_page.path - next_path_suffix = ( - int(max_path[-4:], 36) + 1 - ) # Base-36 to handle alphanumeric paths - next_path = ( - max_path[:-4] + f"{next_path_suffix:04X}" - ) # Convert back to base-36 - else: - next_path = home_page.path + "0001" - with transaction.atomic(): - new_program_page = DistrictNewProgramPage( - title="Programy", - slug="programy", # Make sure the slug is unique among siblings - path=next_path, - depth=home_page.depth + 1, - numchild=0, - content_type_id=new_program_page_content_type.id, - locale_id=default_locale.id, - ) - new_program_page.save() - - # Update numchild on the home page - home_page.numchild = home_page.numchild + 1 - home_page.save(update_fields=["numchild"]) + secondary_candidates_block = { + # Acts as CandidateSecondaryListBlock + "heading": "Další kandidáti", + "candidates": secondary_candidates, + } - election_data["combined_candidates"] = sorted( - election_data["combined_candidates"], - key=lambda value: value["position"], - ) + # if program_data["program_is_inline"]: + + # There's no time left to set this up properly. We'll just use + # inline points for everything, at least for now. + + # Create program point blocks + program_points = [] + + for program_point in program_data["program_points"]: + program_points.append({ # Act as ProgramBlockPopout + "title": program_point["title"], + "content": str(program_point["content"]), + "guarantor": ( + program_point["guarantor_page"].id + if program_point["guarantor_page"] + else None + ) + }) + + program_categories = [{ # Act as ProgramPopoutCategory + "name": program_data["candidate_list_title"], + "point_list": program_points + }] + + program_block = { + "type": "program_group_popout", + "value": { + "title": program_data["program_title"], + "categories": program_categories + } + } - new_program_block = ProgramGroupWithCandidatesBlock().to_python( - { - "title": election_data["title"], - "preamble_content": election_data["program_content_before"], - "primary_candidates": [], - "secondary_candidates": [], - } - ) + # Finally, create a block for this program + new_program_block = ProgramGroupWithCandidatesBlock().to_python( + { + "title": program_data["title"], + "preamble_content": program_data["program_content_before"], + + "primary_candidates": primary_candidates_block, + "secondary_candidates": secondary_candidates_block, + + "program": [program_block] + } + ) - # Stop migration for debugging purposes - raise ValueError("Stopping migration for debugging purposes") + new_program_page.program.append(( + "program_group_with_candidates", + new_program_block + )) + new_program_page.save() class Migration(migrations.Migration): @@ -358,4 +470,16 @@ class Migration(migrations.Migration): ("district", "0217_alter_districthomepage_menu"), ] - operations = [migrations.RunPython(migrate_programs)] + operations = [ + migrations.AlterField( + model_name='districtelectioncampaignpage', + name='candidates', + field=wagtail.fields.StreamField([('candidates', wagtail.blocks.StructBlock([('candidates', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['district.DistrictPersonPage'])), ('image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud není vybrán, použije se obrázek ze stránky kandidáta', label='Obrázek', required=False)), ('description', wagtail.blocks.TextBlock(label='Popis'))]), label=' '))]))], blank=True, verbose_name='Kandidátní listina'), + ), + migrations.AlterField( + model_name='districtnewprogrampage', + name='program', + field=wagtail.fields.StreamField([('program_group', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(label='Odkaz pokrývající celou tuto část', required=False)), ('icon', wagtail.images.blocks.ImageChooserBlock(label='Ikona', required=False)), ('title', wagtail.blocks.CharBlock(label='Titulek článku programu')), ('text', wagtail.blocks.RichTextBlock(features=['h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'document-link', 'image', 'superscript', 'subscript', 'strikethrough', 'blockquote', 'embed'], label='Obsah'))]), label='Jednotlivé články programu'))])), ('program_group_crossroad', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock(label='Obrázek')), ('title', wagtail.blocks.CharBlock(label='Titulek', required=True)), ('text', wagtail.blocks.RichTextBlock(label='Krátký text pod nadpisem', required=False)), ('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['district.DistrictArticlePage', 'district.DistrictArticlesPage', 'district.DistrictCenterPage', 'district.DistrictContactPage', 'district.DistrictCrossroadPage', 'district.DistrictCustomPage', 'district.DistrictElectionCampaignPage', 'district.DistrictElectionProgramPage', 'district.DistrictElectionRootPage', 'district.DistrictPeoplePage', 'district.DistrictPersonPage', 'district.DistrictPostElectionStrategyPage', 'district.DistrictProgramPage'], required=False)), ('link', wagtail.blocks.URLBlock(label='Odkaz', required=False))]), label='Karty programu'))])), ('program_group_popout', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('categories', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('name', wagtail.blocks.CharBlock(label='Název')), ('icon', wagtail.images.blocks.ImageChooserBlock(label='Ikona', required=False)), ('description', wagtail.blocks.RichTextBlock(label='Popis', required=False)), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(label='Titulek vyskakovacího bloku')), ('content', wagtail.blocks.RichTextBlock(features=['h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'document-link', 'image', 'superscript', 'subscript', 'strikethrough', 'blockquote', 'embed'], label='Obsah')), ('guarantor', wagtail.blocks.PageChooserBlock(label='Garant', page_type=['district.DistrictPersonPage'], required=False))]), label='Jednotlivé bloky programu'))]), label='Kategorie programu'))])), ('program_group_with_candidates', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('preamble_content', wagtail.blocks.RichTextBlock(help_text='Text, který se zobrazí před přepínačem mezi kandidáty a programem.', label='Preambule', required=False)), ('primary_candidates', wagtail.blocks.StructBlock([('candidates', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['district.DistrictPersonPage'])), ('image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud není vybrán, použije se obrázek ze stránky kandidáta', label='Obrázek', required=False)), ('description', wagtail.blocks.TextBlock(label='Popis'))]), label=' '))], help_text='Zobrazí se ve velkých blocích na začátku stránky.', label='Osoby na čele kandidátky')), ('secondary_candidates', wagtail.blocks.StructBlock([('heading', wagtail.blocks.CharBlock(default='Ostatní kandidátky', label='Nadpis zbytku kandidátky')), ('candidates', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('number', wagtail.blocks.CharBlock(label='Číslo')), ('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['district.DistrictPersonPage'])), ('image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud není vybrán, použije se obrázek ze stránky kandidáta', label='Obrázek', required=False))]), label='Zbylí kandidáti na listině'))], help_text='Zobrazí se v kompaktním seznamu pod čelem kandidátky.', label='Ostatní osoby na kandidátce')), ('program', wagtail.blocks.StreamBlock([('program_group', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(label='Odkaz pokrývající celou tuto část', required=False)), ('icon', wagtail.images.blocks.ImageChooserBlock(label='Ikona', required=False)), ('title', wagtail.blocks.CharBlock(label='Titulek článku programu')), ('text', wagtail.blocks.RichTextBlock(features=['h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'document-link', 'image', 'superscript', 'subscript', 'strikethrough', 'blockquote', 'embed'], label='Obsah'))]), label='Jednotlivé články programu'))])), ('program_group_crossroad', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock(label='Obrázek')), ('title', wagtail.blocks.CharBlock(label='Titulek', required=True)), ('text', wagtail.blocks.RichTextBlock(label='Krátký text pod nadpisem', required=False)), ('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['district.DistrictArticlePage', 'district.DistrictArticlesPage', 'district.DistrictCenterPage', 'district.DistrictContactPage', 'district.DistrictCrossroadPage', 'district.DistrictCustomPage', 'district.DistrictElectionCampaignPage', 'district.DistrictElectionProgramPage', 'district.DistrictElectionRootPage', 'district.DistrictPeoplePage', 'district.DistrictPersonPage', 'district.DistrictPostElectionStrategyPage', 'district.DistrictProgramPage'], required=False)), ('link', wagtail.blocks.URLBlock(label='Odkaz', required=False))]), label='Karty programu'))])), ('program_group_popout', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('categories', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('name', wagtail.blocks.CharBlock(label='Název')), ('icon', wagtail.images.blocks.ImageChooserBlock(label='Ikona', required=False)), ('description', wagtail.blocks.RichTextBlock(label='Popis', required=False)), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(label='Titulek vyskakovacího bloku')), ('content', wagtail.blocks.RichTextBlock(features=['h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'document-link', 'image', 'superscript', 'subscript', 'strikethrough', 'blockquote', 'embed'], label='Obsah')), ('guarantor', wagtail.blocks.PageChooserBlock(label='Garant', page_type=['district.DistrictPersonPage'], required=False))]), label='Jednotlivé bloky programu'))]), label='Kategorie programu'))]))]))]))], blank=True, verbose_name='Programy'), + ), + migrations.RunPython(migrate_programs) + ] diff --git a/district/models.py b/district/models.py index 5b368e4d..d7a05d9c 100644 --- a/district/models.py +++ b/district/models.py @@ -797,7 +797,7 @@ class DistrictElectionProgramPage( ### RELATIONS - parent_page_types = ["district.DistrictElectionCampaignPage"] + parent_page_types = ["district.DistrictProgramPage"] subpage_types = [] class Meta: diff --git a/elections/migrations/0037_alter_electionshomepage_content.py b/elections/migrations/0037_alter_electionshomepage_content.py new file mode 100644 index 00000000..376270d3 --- /dev/null +++ b/elections/migrations/0037_alter_electionshomepage_content.py @@ -0,0 +1,21 @@ +# Generated by Django 5.0.4 on 2024-06-04 07:28 + +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('elections', '0036_alter_electionshomepage_menu'), + ] + + operations = [ + migrations.AlterField( + model_name='electionshomepage', + name='content', + field=wagtail.fields.StreamField([('carousel', wagtail.blocks.StructBlock([('desktop_image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud není vybráno video, ukáže se na desktopu.', label='Obrázek na pozadí (desktop)')), ('mobile_image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud je vybrán, ukáže se místo videa na mobilu.', label='Obrázek (mobil)', required=False)), ('video_url', wagtail.blocks.URLBlock(help_text='Pokud je vybráno, ukáže se na desktopech s povoleným autoplayem místo obrázku.', label='URL videa', required=False)), ('mobile_line_1', wagtail.blocks.TextBlock(label='První mobilní řádek')), ('mobile_line_2', wagtail.blocks.TextBlock(label='Druhý mobilní řádek'))])), ('candidates', wagtail.blocks.StructBlock([('candidates', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['elections.ElectionsCandidatePage'])), ('image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud není vybrán, použije se obrázek ze stránky kandidáta', label='Obrázek', required=False)), ('description', wagtail.blocks.TextBlock(label='Popis'))]), label='Kandidáti'))])), ('secondary_candidates', wagtail.blocks.StructBlock([('heading', wagtail.blocks.CharBlock(default='Ostatní kandidátky', label='Nadpis zbytku kandidátky')), ('candidates', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('number', wagtail.blocks.CharBlock(label='Číslo')), ('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['elections.ElectionsCandidatePage'])), ('image', wagtail.images.blocks.ImageChooserBlock(help_text='Pokud není vybrán, použije se obrázek ze stránky kandidáta', label='Obrázek', required=False))]), label='Kandidáti'))])), ('program', wagtail.blocks.StructBlock([('label', wagtail.blocks.CharBlock(default='Program', help_text="Např. 'Program'", label='Nadpis')), ('categories', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('number', wagtail.blocks.IntegerBlock(label='Číslo')), ('name', wagtail.blocks.CharBlock(label='Název')), ('points', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('content', wagtail.blocks.TextBlock(label='Obsah'))]), label='Body'))]), label='Kategorie')), ('long_version_url', wagtail.blocks.URLBlock(help_text='Pro zobrazení odkazu na celou verzi programu musí být obě následující pole vyplněná.', label='Odkaz na celou verzi programu', required=False)), ('long_version_text', wagtail.blocks.CharBlock(label='Nadpis odkazu na celou verzi programu', required=False))])), ('news', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text='Nejnovější články se načtou automaticky', label='Titulek')), ('description', wagtail.blocks.TextBlock(label='Popis', required=False))], template='styleguide2/includes/organisms/articles/elections/articles_section.html')), ('calendar', wagtail.blocks.StructBlock([('heading', wagtail.blocks.CharBlock(label='Nadpis'))]))], blank=True, verbose_name='Hlavní obsah'), + ), + ] diff --git a/main/migrations/0094_alter_mainprogrampage_program.py b/main/migrations/0094_alter_mainprogrampage_program.py new file mode 100644 index 00000000..38666500 --- /dev/null +++ b/main/migrations/0094_alter_mainprogrampage_program.py @@ -0,0 +1,21 @@ +# Generated by Django 5.0.4 on 2024-06-04 07:28 + +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0093_alter_mainhomepage_menu'), + ] + + operations = [ + migrations.AlterField( + model_name='mainprogrampage', + name='program', + field=wagtail.fields.StreamField([('program_group', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(label='Odkaz pokrývající celou tuto část', required=False)), ('icon', wagtail.images.blocks.ImageChooserBlock(label='Ikona', required=False)), ('title', wagtail.blocks.CharBlock(label='Titulek článku programu')), ('text', wagtail.blocks.RichTextBlock(features=['h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'document-link', 'image', 'superscript', 'subscript', 'strikethrough', 'blockquote', 'embed'], label='Obsah'))]), label='Jednotlivé články programu'))])), ('program_group_crossroad', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock(label='Obrázek')), ('title', wagtail.blocks.CharBlock(label='Titulek', required=True)), ('text', wagtail.blocks.RichTextBlock(label='Krátký text pod nadpisem', required=False)), ('page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['main.MainArticlesPage', 'main.MainArticlePage', 'main.MainProgramPage', 'main.MainPeoplePage', 'main.MainPersonPage', 'main.MainSimplePage', 'main.MainContactPage', 'main.MainCrossroadPage'], required=False)), ('link', wagtail.blocks.URLBlock(label='Odkaz', required=False))]), label='Karty programu'))])), ('program_group_popout', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('categories', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('name', wagtail.blocks.CharBlock(label='Název')), ('icon', wagtail.images.blocks.ImageChooserBlock(label='Ikona', required=False)), ('description', wagtail.blocks.RichTextBlock(label='Popis', required=False)), ('point_list', wagtail.blocks.ListBlock(wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(label='Titulek vyskakovacího bloku')), ('content', wagtail.blocks.RichTextBlock(features=['h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'document-link', 'image', 'superscript', 'subscript', 'strikethrough', 'blockquote', 'embed'], label='Obsah')), ('guarantor', wagtail.blocks.PageChooserBlock(label='Garant', page_type=['district.DistrictPersonPage'], required=False))]), label='Jednotlivé bloky programu'))]), label='Kategorie programu'))])), ('elections_program', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock(help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...", label='Název programu')), ('program_page', wagtail.blocks.PageChooserBlock(label='Stránka', page_type=['elections.ElectionsFullProgramPage'], required=False))]))], blank=True, verbose_name='Programy'), + ), + ] -- GitLab