From 9f01649b23dcec8d93aa2504f0542506ea116bf9 Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Tue, 30 Jun 2026 12:13:25 -0700 Subject: [PATCH 1/2] Remove LeadershipPage Model [WT-1389] --- bedrock/mozorg/blocks/leadership.py | 124 ------------------ .../migrations/0043_delete_leadershippage.py | 20 +++ ...044_delete_leadershippage_contentmodels.py | 28 ++++ bedrock/mozorg/models.py | 20 --- 4 files changed, 48 insertions(+), 144 deletions(-) create mode 100644 bedrock/mozorg/migrations/0043_delete_leadershippage.py create mode 100644 bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py diff --git a/bedrock/mozorg/blocks/leadership.py b/bedrock/mozorg/blocks/leadership.py index 0463655e699..8fca13bfc6b 100644 --- a/bedrock/mozorg/blocks/leadership.py +++ b/bedrock/mozorg/blocks/leadership.py @@ -3,36 +3,11 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. from django.conf import settings -from django.template.defaultfilters import slugify as django_slugify from wagtail import blocks -from wagtail.images.blocks import ImageChooserBlock from wagtail.snippets.blocks import SnippetChooserBlock -class LeadershipHeadshotBlock(blocks.StructBlock): - """Block for a leadership bio headshot image and (optional) photos link.""" - - image = ImageChooserBlock( - help_text="A headshot image of the person.", - ) - - image_alt_text = blocks.CharBlock( - char_max_length=255, - help_text="Alt text for the headshot image.", - ) - - photos_link = blocks.URLBlock( - required=False, - char_max_length=255, - help_text="External link to a .zip file of photos of the person.", - ) - - class Meta: - icon = "image" - label = "Headshot image" - - class LeadershipExternalLinkBlock(blocks.StructBlock): """Block for a leadership bio external link, such as a website or social media account.""" @@ -63,105 +38,6 @@ class Meta: label = "External Link" -class LeadershipBioID(blocks.StructValue): - """ID Value class for LeadershipBioBlock. Used for page anchor links.""" - - @property - def id(self): - name = self.get("name") - return django_slugify(name) - - -class LeadershipBioBlock(blocks.StructBlock): - """Block for a leadership bio.""" - - name = blocks.CharBlock( - char_max_length=255, - placeholder="Enter the person's full name.", - ) - - headshot = LeadershipHeadshotBlock() - - job_title = blocks.CharBlock( - required=False, - char_max_length=255, - ) - - biography = blocks.RichTextBlock( - required=False, - help_text="A biography limited to a few short paragraphs. Links and formatting are supported.", - features=settings.WAGTAIL_RICHTEXT_FEATURES_FULL, - ) - - external_links = blocks.ListBlock( - LeadershipExternalLinkBlock(), - min_num=0, - max_num=5, - ) - - class Meta: - value_class = LeadershipBioID - template = "mozorg/cms/about/blocks/leadership_block.html" - icon = "user" - label = "Leadership Profile" - - -class LeadershipGroupBlock(blocks.StructBlock): - """Block for a leadership group.""" - - title = blocks.CharBlock( - char_max_length=255, - help_text="Leadership group title, e.g. 'Executive Steering Committee' or 'Senior Leadership'.", - required=False, - ) - - description = blocks.CharBlock( - char_max_length=1000, - help_text="A couple of sentences describes what the group is and some helpful context.", - required=False, - ) - - leaders = blocks.ListBlock( - LeadershipBioBlock(), - min_num=1, - ) - - class Meta: - icon = "group" - - -class LeadershipSectionID(blocks.StructValue): - """ID Value class for LeadershipSectionBlock. Used for page anchor links.""" - - @property - def id(self): - name = self.get("title") - return django_slugify(name) - - -class LeadershipSectionBlock(blocks.StructBlock): - """Block for a leadership section containing a title and one or more leadership groups.""" - - title = blocks.CharBlock( - max_length=255, blank=True, null=True, help_text="Title for the section of the page e.g. 'Mozilla Corporation' or 'Mozilla Foundation." - ) - - description = blocks.CharBlock( - char_max_length=1000, - help_text="Description for the leadership section.", - required=False, - ) - - leadership_group = blocks.ListBlock( - LeadershipGroupBlock(), - min_num=1, - ) - - class Meta: - value_class = LeadershipSectionID - icon = "group" - - class LeadershipProfileChooserBlock(blocks.StructBlock): """Block for placing a LeadershipProfileSnippet with an optional per-placement job title.""" diff --git a/bedrock/mozorg/migrations/0043_delete_leadershippage.py b/bedrock/mozorg/migrations/0043_delete_leadershippage.py new file mode 100644 index 00000000000..afab3a40dda --- /dev/null +++ b/bedrock/mozorg/migrations/0043_delete_leadershippage.py @@ -0,0 +1,20 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +# Generated by Django 5.2.14 on 2026-06-30 19:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mozorg', '0042_alter_organizationleadershipsubpage_leadership_groups'), + ] + + operations = [ + migrations.DeleteModel( + name='LeadershipPage', + ), + ] diff --git a/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py b/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py new file mode 100644 index 00000000000..547d5082307 --- /dev/null +++ b/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py @@ -0,0 +1,28 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +from django.db import migrations + +STALE_MODELS = ( + "LeadershipPage", +) + + +def remove_stale_contenttypes(apps, schema_editor): + # Migration 0043 dropped LeadershipPage + # but Django doesn't auto-purge the django_content_type rows for deleted models. Anything + # that resolves a log entry / permission via ContentType.get_object_for_this_type() (e.g. + # the Wagtail admin home recent-edits panel) then crashes because model_class() is None. + ContentType = apps.get_model("contenttypes", "ContentType") + ContentType.objects.filter(app_label="cms", model__in=STALE_MODELS).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("mozorg", "0043_delete_leadershippage"), + ] + + operations = [ + migrations.RunPython(remove_stale_contenttypes, reverse_code=migrations.RunPython.noop), + ] diff --git a/bedrock/mozorg/models.py b/bedrock/mozorg/models.py index 6c60c9c2c16..095f7673870 100644 --- a/bedrock/mozorg/models.py +++ b/bedrock/mozorg/models.py @@ -27,7 +27,6 @@ LeadershipExternalLinkBlock, LeadershipGroupSnippetBlock, LeadershipProfileChooserBlock, - LeadershipSectionBlock, ) from bedrock.mozorg.blocks.navigation import NavigationLinkBlock @@ -329,25 +328,6 @@ def __str__(self): return self.name -class LeadershipPage(AbstractBedrockCMSPage): - max_count = 1 # Ensure there's only one instance of this page - subpage_types = [] # This page type cannot have any children - - leadership_sections = StreamField( - [("section", LeadershipSectionBlock())], - blank=True, - null=True, - collapsed=True, - use_json_field=True, - ) - - content_panels = AbstractBedrockCMSPage.content_panels + [ - FieldPanel("leadership_sections"), - ] - - template = "mozorg/cms/about/leadership.html" - - class OrganizationLeadershipIndexPage(AbstractBedrockCMSPage): subpage_types = ["OrganizationLeadershipSubpage"] From 0120208cee5e46bf8c169d3b29e3a58f5459c891 Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Thu, 2 Jul 2026 13:22:01 -0700 Subject: [PATCH 2/2] Review fixes Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../migrations/0044_delete_leadershippage_contentmodels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py b/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py index 547d5082307..33db9b418b3 100644 --- a/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py +++ b/bedrock/mozorg/migrations/0044_delete_leadershippage_contentmodels.py @@ -5,7 +5,7 @@ from django.db import migrations STALE_MODELS = ( - "LeadershipPage", + "leadershippage", ) @@ -15,7 +15,7 @@ def remove_stale_contenttypes(apps, schema_editor): # that resolves a log entry / permission via ContentType.get_object_for_this_type() (e.g. # the Wagtail admin home recent-edits panel) then crashes because model_class() is None. ContentType = apps.get_model("contenttypes", "ContentType") - ContentType.objects.filter(app_label="cms", model__in=STALE_MODELS).delete() + ContentType.objects.filter(app_label="mozorg", model__in=STALE_MODELS).delete() class Migration(migrations.Migration):