diff --git a/bedrock/mozorg/blocks/common.py b/bedrock/mozorg/blocks/common.py index a8a2ae78023..7f7a67f7dbb 100644 --- a/bedrock/mozorg/blocks/common.py +++ b/bedrock/mozorg/blocks/common.py @@ -340,13 +340,23 @@ class ShowcaseBlock(blocks.StructBlock): ) sub_heading = blocks.CharBlock( + required=False, max_length=255, help_text="Section sub heading heading. Use sentence case.", ) + two_column_layout = blocks.BooleanBlock( + required=False, + default=False, + label="Make it two column layout", + inline_form=True, + help_text="Make the title and body content into a two-column layout.", + ) + cta_divider = DividerBlock(label="Call-to-action") cta_text = blocks.CharBlock( + required=False, max_length=50, label="Link text", help_text="Use sentence case (e.g., 'Read the report', 'Read more').", @@ -486,6 +496,26 @@ class Meta: label_format = "{heading} ({width})" +class ShowcaseGalleryImageBlock(blocks.StructBlock): + """A single image with alt text for the gallery.""" + + image = ImageChooserBlock() + + image_alt = blocks.CharBlock( + max_length=255, + required=False, + help_text=( + "A concise description of the image for someone who can't see it. " + "See alt text guidelines for tips." + ), + ) + + class Meta: + icon = "image" + label = "Showcase Gallery Image" + label_format = "{image}" + + class GalleryBlock(blocks.StructBlock): """Block for a gallery section with multiple tiles.""" @@ -512,3 +542,78 @@ class Meta: icon = "grip" label = "Gallery Section" label_format = "{heading}" + + +class ShowcaseGalleryBlockSettings(blocks.StructBlock): + """Settings for the showcase gallery block.""" + + anchor_id = blocks.CharBlock( + required=False, + max_length=100, + help_text="Optional: Add an ID to make this section linkable (e.g., 'news', 'gallery').", + ) + + background_color = blocks.ChoiceBlock( + choices=[ + ("", "White"), + ("m24-t-dark", "Dark"), + ("m24-t-green", "Green"), + ("m24-t-orange", "Orange"), + ("m24-t-pink", "Pink"), + ("m24-t-gray", "Gray"), + ], + required=False, + help_text="What color should the background be?", + ) + + class Meta: + icon = "cog" + collapsed = True + label = "Settings" + label_format = "ID: {anchor_id} - Background: {background_color}" + form_classname = "compact-form struct-block" + + +class ShowcaseGalleryBlock(blocks.StructBlock): + """A showcase block with a gallery as media.""" + + settings = ShowcaseGalleryBlockSettings() + + text_divider = DividerBlock(label="Text") + + heading = blocks.CharBlock( + required=False, + max_length=255, + help_text="Use sentence case.", + ) + + image_divider = DividerBlock(label="Image") + + tiles = blocks.ListBlock( + ShowcaseGalleryImageBlock(), + min_num=1, + help_text="Add gallery tiles. For best results, ensure tile widths add up to 100% per row.", + ) + + body = blocks.CharBlock( + max_length=1000, + label="Content for section body", + help_text="Use sentence case.", + ) + + cta_text = blocks.CharBlock( + required=False, + max_length=50, + label="Link text", + help_text="Use sentence case (e.g., 'Read the report', 'Read more').", + ) + + cta_link = LinkBlock( + label="Link destination", + ) + + class Meta: + template = "mozorg/cms/blocks/showcase_gallery_block.html" + icon = "grip" + label = "Showcase Gallery section" + label_format = "{heading}" diff --git a/bedrock/mozorg/fixtures/showcase_gallery_fixtures.py b/bedrock/mozorg/fixtures/showcase_gallery_fixtures.py new file mode 100644 index 00000000000..dc8388f01e7 --- /dev/null +++ b/bedrock/mozorg/fixtures/showcase_gallery_fixtures.py @@ -0,0 +1,140 @@ +# 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 bedrock.mozorg.fixtures.base_fixtures import get_placeholder_image, get_test_index_page +from bedrock.mozorg.models import AboutUsPage + + +def get_showcase_gallery_variants(image_id: int) -> list[dict]: + """Return list of ShowcaseGalleryBlock data variants for testing. + + Args: + image_id: ID of the placeholder image to use + + Returns: + List of block data dictionaries representing different configurations + """ + return [ + # Variant 1: Default white background, no anchor, multiple tiles + { + "type": "showcase_gallery_block", + "value": { + "settings": { + "background_color": "", + "anchor_id": "", + }, + "heading": "Working at Mozilla", + "tiles": [ + {"image": image_id, "image_alt": "Mozilla team working together"}, + {"image": image_id, "image_alt": "Mozilla office space"}, + {"image": image_id, "image_alt": "Mozilla team event"}, + {"image": image_id, "image_alt": ""}, + ], + "body": "Join a team that believes the internet is for everyone.", + "cta_text": "See open roles", + "cta_link": { + "link_to": "custom_url", + "custom_url": "https://www.mozilla.org/careers", + "new_window": False, + }, + }, + "id": "showcase-gallery-variant-1", + }, + # Variant 2: Dark background + { + "type": "showcase_gallery_block", + "value": { + "settings": { + "background_color": "m24-t-dark", + "anchor_id": "", + }, + "heading": "Our Culture", + "tiles": [ + {"image": image_id, "image_alt": "Mozilla culture photo"}, + {"image": image_id, "image_alt": ""}, + ], + "body": "A mission-driven organization where your work matters.", + "cta_text": "Learn about our culture", + "cta_link": { + "link_to": "custom_url", + "custom_url": "https://www.mozilla.org/about/culture", + "new_window": False, + }, + }, + "id": "showcase-gallery-variant-2", + }, + # Variant 3: Green background with anchor_id + { + "type": "showcase_gallery_block", + "value": { + "settings": { + "background_color": "m24-t-green", + "anchor_id": "careers-section", + }, + "heading": "Benefits and Perks", + "tiles": [ + {"image": image_id, "image_alt": "Employee benefits"}, + {"image": image_id, "image_alt": "Flexible working"}, + ], + "body": "We offer competitive benefits that support your whole life.", + "cta_text": "View benefits", + "cta_link": { + "link_to": "custom_url", + "custom_url": "https://www.mozilla.org/careers/benefits", + "new_window": False, + }, + }, + "id": "showcase-gallery-variant-3", + }, + # Variant 4: Orange background, new_window=True + { + "type": "showcase_gallery_block", + "value": { + "settings": { + "background_color": "m24-t-orange", + "anchor_id": "", + }, + "heading": "Join Mozilla", + "tiles": [ + {"image": image_id, "image_alt": "Mozilla team photo"}, + {"image": image_id, "image_alt": "Mozilla campus"}, + ], + "body": "Help us keep the internet open and accessible.", + "cta_text": "Apply now", + "cta_link": { + "link_to": "custom_url", + "custom_url": "https://www.mozilla.org/careers/apply", + "new_window": True, + }, + }, + "id": "showcase-gallery-variant-4", + }, + ] + + +def get_showcase_gallery_test_page() -> AboutUsPage: + """Create an AboutUsPage with all showcase gallery block variants for testing. + + Returns: + AboutUsPage instance with showcase gallery blocks populated + """ + placeholder_image = get_placeholder_image() + variants = get_showcase_gallery_variants(placeholder_image.id) + index_page = get_test_index_page() + + test_page = AboutUsPage.objects.filter(slug="showcase-gallery-block-test").first() + if test_page: + return test_page + + test_page = AboutUsPage( + title="Showcase Gallery Block Test Page", + slug="showcase-gallery-block-test", + content=variants, + ) + + index_page.add_child(instance=test_page) + test_page.save_revision().publish() + + return test_page diff --git a/bedrock/mozorg/migrations/0027_aboutuspage_alter_homepage_content.py b/bedrock/mozorg/migrations/0027_aboutuspage_alter_homepage_content.py new file mode 100644 index 00000000000..f2b9a65aefd --- /dev/null +++ b/bedrock/mozorg/migrations/0027_aboutuspage_alter_homepage_content.py @@ -0,0 +1,37 @@ +# 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.13 on 2026-04-16 15:37 + +import django.db.models.deletion +import wagtail.admin.forms.choosers +import wagtail.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mozorg', '0026_alter_notificationsnippet_notification_text'), + ('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='AboutUsPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ('content', wagtail.fields.StreamField([('donate_block', 20), ('gallery_block', 34), ('showcase_block', 42), ('showcase_gallery_block', 48), ('transition_block', 50)], blank=True, block_lookup={0: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'donate', 'support').", 'max_length': 100, 'required': False}), 1: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('', 'White'), ('m24-t-dark', 'Dark'), ('m24-t-green', 'Green'), ('m24-t-orange', 'Orange'), ('m24-t-pink', 'Pink'), ('m24-t-gray', 'Gray')], 'help_text': 'What color should the background be?', 'required': False}), 2: ('wagtail.blocks.StructBlock', [[('anchor_id', 0), ('background_color', 1)]], {}), 3: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Text'}), 4: ('wagtail.blocks.CharBlock', (), {'help_text': 'Use sentence case.', 'max_length': 255}), 5: ('wagtail.blocks.RichTextBlock', (), {'features': ['bold', 'link'], 'help_text': 'Keep this to 2 paragraphs or fewer.'}), 6: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Image'}), 7: ('wagtail.images.blocks.ImageChooserBlock', (), {'help_text': 'Ideal image size is 1400 x 700. Image will be cropped to a 2:1 aspect ratio.'}), 8: ('wagtail.blocks.CharBlock', (), {'help_text': "A concise description of the image for someone who can't see it. See alt text guidelines for tips.", 'max_length': 255, 'required': False}), 9: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Call-to-action'}), 10: ('wagtail.blocks.CharBlock', (), {'help_text': "Use sentence case (e.g., 'Donate', 'Read more').", 'label': 'Link text', 'max_length': 50}), 11: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('page', 'Page'), ('file', 'File'), ('custom_url', 'Custom URL'), ('email', 'Email'), ('anchor', 'Anchor'), ('phone', 'Phone')], 'classname': 'link_choice_type_selector', 'label': 'Link to', 'required': False}), 12: ('wagtail.blocks.PageChooserBlock', (), {'form_classname': 'page_link', 'label': 'Page', 'required': False}), 13: ('wagtail.documents.blocks.DocumentChooserBlock', (), {'form_classname': 'file_link', 'label': 'File', 'required': False}), 14: ('wagtail.blocks.CharBlock', (), {'form_classname': 'custom_url_link url_field', 'label': 'Custom URL', 'max_length': 300, 'required': False, 'validators': [wagtail.admin.forms.choosers.URLOrAbsolutePathValidator()]}), 15: ('wagtail.blocks.CharBlock', (), {'form_classname': 'anchor_link', 'label': '#', 'max_length': 300, 'required': False}), 16: ('wagtail.blocks.EmailBlock', (), {'required': False}), 17: ('wagtail.blocks.CharBlock', (), {'form_classname': 'phone_link', 'label': 'Phone', 'max_length': 30, 'required': False}), 18: ('wagtail.blocks.BooleanBlock', (), {'form_classname': 'new_window_toggle', 'label': 'Open in new window', 'required': False}), 19: ('wagtail.blocks.StructBlock', [[('link_to', 11), ('page', 12), ('file', 13), ('custom_url', 14), ('anchor', 15), ('email', 16), ('phone', 17), ('new_window', 18)]], {'label': 'Link destination'}), 20: ('wagtail.blocks.StructBlock', [[('settings', 2), ('text_divider', 3), ('heading', 4), ('body', 5), ('image_divider', 6), ('image', 7), ('image_alt', 8), ('cta_divider', 9), ('cta_text', 10), ('cta_link', 19)]], {}), 21: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'news', 'gallery').", 'max_length': 100, 'required': False}), 22: ('wagtail.blocks.StructBlock', [[('anchor_id', 21), ('background_color', 1)]], {}), 23: ('wagtail.blocks.CharBlock', (), {'max_length': 255, 'required': False}), 24: ('wagtail.blocks.RichTextBlock', (), {'features': ['bold', 'link'], 'required': False}), 25: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('fifth', 'Fifth (20%)'), ('quarter', 'Quarter (25%)'), ('third', 'Third (33%)'), ('half', 'Half (50%)'), ('three-quarters', 'Three-quarters (75%)')], 'help_text': 'Width of the tile in the gallery grid at desktop sizes.'}), 26: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Link'}), 27: ('wagtail.images.blocks.ImageChooserBlock', (), {'help_text': 'Upload a 2:1 aspect ratio image at 1400×700px - this is displayed on mobile browsers. Wagtail will crop it for displaying at your chosen aspect ratios for desktop.'}), 28: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('2:1', '2:1 Wide landscape'), ('1:1', '1:1 Square'), ('5:4', '5:4 Landscape'), ('4:5', '4:5 Portrait'), ('2:3', '2:3 Tall portrait')], 'help_text': 'Aspect ratio for the image on desktop. The image will be cropped to fit.'}), 29: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('', 'None'), ('community', 'Community'), ('event', 'Event'), ('impact', 'Impact'), ('partnership', 'Partnership'), ('policy', 'Policy'), ('product', 'Product'), ('program', 'Program'), ('project', 'Project'), ('research', 'Research')], 'required': False}), 30: ('wagtail.blocks.TextBlock', (), {'help_text': "Short blurb about what you're linking to.", 'required': False}), 31: ('wagtail.blocks.CharBlock', (), {'help_text': "Use sentence case (e.g., 'Read more', 'Watch now').", 'label': 'Call to action text (optional)', 'max_length': 100, 'required': False}), 32: ('wagtail.blocks.StructBlock', [[('width', 25), ('link_divider', 26), ('cta_link', 19), ('image_divider', 6), ('image', 27), ('image_ratio', 28), ('image_alt', 8), ('text_divider', 3), ('tag', 29), ('heading', 4), ('body', 30), ('cta_text', 31)]], {}), 33: ('wagtail.blocks.ListBlock', (32,), {'help_text': 'Add gallery tiles. For best results, ensure tile widths add up to 100% per row.', 'min_num': 1}), 34: ('wagtail.blocks.StructBlock', [[('settings', 22), ('heading', 23), ('intro', 24), ('tiles', 33)]], {}), 35: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'showcase', 'support').", 'max_length': 100, 'required': False}), 36: ('wagtail.blocks.StructBlock', [[('anchor_id', 35), ('background_color', 1)]], {}), 37: ('wagtail.blocks.CharBlock', (), {'help_text': 'Section heading. Use sentence case.', 'max_length': 255}), 38: ('wagtail.images.blocks.ImageChooserBlock', (), {'help_text': 'Ideal image size is 1376 * 515.'}), 39: ('wagtail.blocks.CharBlock', (), {'help_text': 'Section sub heading heading. Use sentence case.', 'max_length': 255, 'required': False}), 40: ('wagtail.blocks.BooleanBlock', (), {'default': False, 'help_text': 'Make the title and body content into a two-column layout.', 'inline_form': True, 'label': 'Make it two column layout', 'required': False}), 41: ('wagtail.blocks.CharBlock', (), {'help_text': "Use sentence case (e.g., 'Read the report', 'Read more').", 'label': 'Link text', 'max_length': 50, 'required': False}), 42: ('wagtail.blocks.StructBlock', [[('settings', 36), ('text_divider', 3), ('heading', 37), ('body', 5), ('image_divider', 6), ('image', 38), ('image_alt', 8), ('sub_heading', 39), ('two_column_layout', 40), ('cta_divider', 9), ('cta_text', 41), ('cta_link', 19)]], {}), 43: ('wagtail.blocks.CharBlock', (), {'help_text': 'Use sentence case.', 'max_length': 255, 'required': False}), 44: ('wagtail.images.blocks.ImageChooserBlock', (), {}), 45: ('wagtail.blocks.StructBlock', [[('image', 44), ('image_alt', 8)]], {}), 46: ('wagtail.blocks.ListBlock', (45,), {'help_text': 'Add gallery tiles. For best results, ensure tile widths add up to 100% per row.', 'min_num': 1}), 47: ('wagtail.blocks.CharBlock', (), {'help_text': 'Use sentence case.', 'label': 'Content for section body', 'max_length': 1000}), 48: ('wagtail.blocks.StructBlock', [[('settings', 22), ('text_divider', 3), ('heading', 43), ('image_divider', 6), ('tiles', 46), ('body', 47), ('cta_text', 41), ('cta_link', 19)]], {}), 49: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('light', 'White'), ('dark', 'Dark'), ('green', 'Green'), ('orange', 'Orange'), ('pink', 'Pink'), ('gray', 'Gray')]}), 50: ('wagtail.blocks.StructBlock', [[('top_color', 49), ('bottom_color', 49)]], {})}, help_text='Add content blocks for the homepage. Blocks will render in the order shown.', null=True)), + ], + options={ + 'verbose_name': 'About Us Page', + }, + bases=('wagtailcore.page',), + ), + migrations.AlterField( + model_name='homepage', + name='content', + field=wagtail.fields.StreamField([('springboard_block', 18), ('donate_block', 37), ('gallery_block', 51), ('showcase_block', 59), ('transition_block', 61)], blank=True, block_lookup={0: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'media', 'support').", 'max_length': 100, 'required': False}), 1: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('', 'White'), ('m24-t-dark', 'Dark'), ('m24-t-green', 'Green'), ('m24-t-orange', 'Orange'), ('m24-t-pink', 'Pink'), ('m24-t-gray', 'Gray')], 'help_text': 'What color should the background be?', 'required': False}), 2: ('wagtail.blocks.StructBlock', [[('anchor_id', 0), ('background_color', 1)]], {}), 3: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Text'}), 4: ('wagtail.blocks.CharBlock', (), {'help_text': 'Use sentence case.', 'max_length': 255, 'required': False}), 5: ('wagtail.blocks.CharBlock', (), {'help_text': 'Column name, e.g.: Type', 'label': 'Title for column one', 'max_length': 255}), 6: ('wagtail.blocks.CharBlock', (), {'help_text': 'Column name, e.g.: Author(s)', 'label': 'Title for column two', 'max_length': 255}), 7: ('wagtail.blocks.CharBlock', (), {'help_text': 'Column name, e.g.: Topic', 'label': 'Title for column three', 'max_length': 255}), 8: ('wagtail.blocks.CharBlock', (), {'help_text': 'Column name, e.g.: Intro', 'label': 'Title for column four', 'max_length': 255}), 9: ('wagtail.blocks.URLBlock', (), {'char_max_length': 255, 'help_text': "Link to the person's website or social media account with UTMs.", 'required': True}), 10: ('wagtail.blocks.CharBlock', (), {'char_max_length': 255, 'help_text': 'Link attributes limited to data-* (e.g., data-link-text="...", data-link-position="...")', 'required': False}), 11: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('Article', 'Article'), ('Podcast', 'Podcast'), ('Video', 'Video')], 'help_text': 'Selects a visual icon type for the link.', 'required': False}), 12: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('article', 'Article'), ('podcast', 'Podcast'), ('video', 'Video')], 'help_text': 'Selects an icon for the row.', 'required': False}), 13: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('News', 'News'), ('Products', 'Products'), ('Artificial Intelligence', 'Artificial Intelligence'), ('Open Source AI', 'Open Source AI'), ('Privacy & Security', 'Privacy & Security')], 'help_text': 'Selects a topic.', 'required': False}), 14: ('wagtail.blocks.CharBlock', (), {'char_max_length': 255, 'help_text': 'Author name(s), website name', 'required': False}), 15: ('wagtail.blocks.CharBlock', (), {'char_max_length': 255, 'help_text': 'Short preview of the content', 'required': False}), 16: ('wagtail.blocks.StructBlock', [[('url', 9), ('link_attributes', 10), ('type', 11), ('icon', 12), ('topic', 13), ('author', 14), ('preview', 15)]], {}), 17: ('wagtail.blocks.ListBlock', (16,), {'min_num': 1}), 18: ('wagtail.blocks.StructBlock', [[('settings', 2), ('text_divider', 3), ('heading', 4), ('column_one', 5), ('column_two', 6), ('column_three', 7), ('column_four', 8), ('springboard_items', 17)]], {}), 19: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'donate', 'support').", 'max_length': 100, 'required': False}), 20: ('wagtail.blocks.StructBlock', [[('anchor_id', 19), ('background_color', 1)]], {}), 21: ('wagtail.blocks.CharBlock', (), {'help_text': 'Use sentence case.', 'max_length': 255}), 22: ('wagtail.blocks.RichTextBlock', (), {'features': ['bold', 'link'], 'help_text': 'Keep this to 2 paragraphs or fewer.'}), 23: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Image'}), 24: ('wagtail.images.blocks.ImageChooserBlock', (), {'help_text': 'Ideal image size is 1400 x 700. Image will be cropped to a 2:1 aspect ratio.'}), 25: ('wagtail.blocks.CharBlock', (), {'help_text': "A concise description of the image for someone who can't see it. See alt text guidelines for tips.", 'max_length': 255, 'required': False}), 26: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Call-to-action'}), 27: ('wagtail.blocks.CharBlock', (), {'help_text': "Use sentence case (e.g., 'Donate', 'Read more').", 'label': 'Link text', 'max_length': 50}), 28: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('page', 'Page'), ('file', 'File'), ('custom_url', 'Custom URL'), ('email', 'Email'), ('anchor', 'Anchor'), ('phone', 'Phone')], 'classname': 'link_choice_type_selector', 'label': 'Link to', 'required': False}), 29: ('wagtail.blocks.PageChooserBlock', (), {'form_classname': 'page_link', 'label': 'Page', 'required': False}), 30: ('wagtail.documents.blocks.DocumentChooserBlock', (), {'form_classname': 'file_link', 'label': 'File', 'required': False}), 31: ('wagtail.blocks.CharBlock', (), {'form_classname': 'custom_url_link url_field', 'label': 'Custom URL', 'max_length': 300, 'required': False, 'validators': [wagtail.admin.forms.choosers.URLOrAbsolutePathValidator()]}), 32: ('wagtail.blocks.CharBlock', (), {'form_classname': 'anchor_link', 'label': '#', 'max_length': 300, 'required': False}), 33: ('wagtail.blocks.EmailBlock', (), {'required': False}), 34: ('wagtail.blocks.CharBlock', (), {'form_classname': 'phone_link', 'label': 'Phone', 'max_length': 30, 'required': False}), 35: ('wagtail.blocks.BooleanBlock', (), {'form_classname': 'new_window_toggle', 'label': 'Open in new window', 'required': False}), 36: ('wagtail.blocks.StructBlock', [[('link_to', 28), ('page', 29), ('file', 30), ('custom_url', 31), ('anchor', 32), ('email', 33), ('phone', 34), ('new_window', 35)]], {'label': 'Link destination'}), 37: ('wagtail.blocks.StructBlock', [[('settings', 20), ('text_divider', 3), ('heading', 21), ('body', 22), ('image_divider', 23), ('image', 24), ('image_alt', 25), ('cta_divider', 26), ('cta_text', 27), ('cta_link', 36)]], {}), 38: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'news', 'gallery').", 'max_length': 100, 'required': False}), 39: ('wagtail.blocks.StructBlock', [[('anchor_id', 38), ('background_color', 1)]], {}), 40: ('wagtail.blocks.CharBlock', (), {'max_length': 255, 'required': False}), 41: ('wagtail.blocks.RichTextBlock', (), {'features': ['bold', 'link'], 'required': False}), 42: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('fifth', 'Fifth (20%)'), ('quarter', 'Quarter (25%)'), ('third', 'Third (33%)'), ('half', 'Half (50%)'), ('three-quarters', 'Three-quarters (75%)')], 'help_text': 'Width of the tile in the gallery grid at desktop sizes.'}), 43: ('bedrock.mozorg.blocks.common.DividerBlock', (), {'label': 'Link'}), 44: ('wagtail.images.blocks.ImageChooserBlock', (), {'help_text': 'Upload a 2:1 aspect ratio image at 1400×700px - this is displayed on mobile browsers. Wagtail will crop it for displaying at your chosen aspect ratios for desktop.'}), 45: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('2:1', '2:1 Wide landscape'), ('1:1', '1:1 Square'), ('5:4', '5:4 Landscape'), ('4:5', '4:5 Portrait'), ('2:3', '2:3 Tall portrait')], 'help_text': 'Aspect ratio for the image on desktop. The image will be cropped to fit.'}), 46: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('', 'None'), ('community', 'Community'), ('event', 'Event'), ('impact', 'Impact'), ('partnership', 'Partnership'), ('policy', 'Policy'), ('product', 'Product'), ('program', 'Program'), ('project', 'Project'), ('research', 'Research')], 'required': False}), 47: ('wagtail.blocks.TextBlock', (), {'help_text': "Short blurb about what you're linking to.", 'required': False}), 48: ('wagtail.blocks.CharBlock', (), {'help_text': "Use sentence case (e.g., 'Read more', 'Watch now').", 'label': 'Call to action text (optional)', 'max_length': 100, 'required': False}), 49: ('wagtail.blocks.StructBlock', [[('width', 42), ('link_divider', 43), ('cta_link', 36), ('image_divider', 23), ('image', 44), ('image_ratio', 45), ('image_alt', 25), ('text_divider', 3), ('tag', 46), ('heading', 21), ('body', 47), ('cta_text', 48)]], {}), 50: ('wagtail.blocks.ListBlock', (49,), {'help_text': 'Add gallery tiles. For best results, ensure tile widths add up to 100% per row.', 'min_num': 1}), 51: ('wagtail.blocks.StructBlock', [[('settings', 39), ('heading', 40), ('intro', 41), ('tiles', 50)]], {}), 52: ('wagtail.blocks.CharBlock', (), {'help_text': "Optional: Add an ID to make this section linkable (e.g., 'showcase', 'support').", 'max_length': 100, 'required': False}), 53: ('wagtail.blocks.StructBlock', [[('anchor_id', 52), ('background_color', 1)]], {}), 54: ('wagtail.blocks.CharBlock', (), {'help_text': 'Section heading. Use sentence case.', 'max_length': 255}), 55: ('wagtail.images.blocks.ImageChooserBlock', (), {'help_text': 'Ideal image size is 1376 * 515.'}), 56: ('wagtail.blocks.CharBlock', (), {'help_text': 'Section sub heading heading. Use sentence case.', 'max_length': 255, 'required': False}), 57: ('wagtail.blocks.BooleanBlock', (), {'default': False, 'help_text': 'Make the title and body content into a two-column layout.', 'inline_form': True, 'label': 'Make it two column layout', 'required': False}), 58: ('wagtail.blocks.CharBlock', (), {'help_text': "Use sentence case (e.g., 'Read the report', 'Read more').", 'label': 'Link text', 'max_length': 50, 'required': False}), 59: ('wagtail.blocks.StructBlock', [[('settings', 53), ('text_divider', 3), ('heading', 54), ('body', 22), ('image_divider', 23), ('image', 55), ('image_alt', 25), ('sub_heading', 56), ('two_column_layout', 57), ('cta_divider', 26), ('cta_text', 58), ('cta_link', 36)]], {}), 60: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('light', 'White'), ('dark', 'Dark'), ('green', 'Green'), ('orange', 'Orange'), ('pink', 'Pink'), ('gray', 'Gray')]}), 61: ('wagtail.blocks.StructBlock', [[('top_color', 60), ('bottom_color', 60)]], {})}, help_text='Add content blocks for the homepage. Blocks will render in the order shown.', null=True), + ), + ] diff --git a/bedrock/mozorg/models.py b/bedrock/mozorg/models.py index 08c03984608..33ce5eef72e 100644 --- a/bedrock/mozorg/models.py +++ b/bedrock/mozorg/models.py @@ -20,7 +20,7 @@ SectionBlock, TwoColumnDetailBlock, ) -from bedrock.mozorg.blocks.common import DonateBlock, GalleryBlock, ShowcaseBlock, SpringboardBlock, TransitionBlock +from bedrock.mozorg.blocks.common import DonateBlock, GalleryBlock, ShowcaseBlock, ShowcaseGalleryBlock, SpringboardBlock, TransitionBlock from bedrock.mozorg.blocks.leadership import LeadershipSectionBlock from bedrock.mozorg.blocks.navigation import NavigationLinkBlock @@ -461,3 +461,47 @@ def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["utm_parameters"] = self.get_utm_parameters() return context + + +class AboutUsPage(AbstractBedrockCMSPage): + subpage_types = [ + LeadershipPage, + ] + + max_count = 1 # Ensure there's only one instance of this page + ftl_files = ["mozorg/about-m24"] + + content = StreamField( + [ + ("donate_block", DonateBlock()), + ("gallery_block", GalleryBlock()), + ("showcase_block", ShowcaseBlock()), + ("showcase_gallery_block", ShowcaseGalleryBlock()), + ("transition_block", TransitionBlock()), + ], + blank=True, + null=True, + use_json_field=True, + help_text="Add content blocks for the homepage. Blocks will render in the order shown.", + ) + + content_panels = [ + FieldPanel("title", help_text="Help identify this page for other editors."), + FieldPanel("content"), + ] + + template = "mozorg/cms/about/about-us.html" + + def get_utm_parameters(self): + return { + **BASE_UTM_PARAMETERS, + "utm_campaign": self.slug or "about-us", + } + + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + context["utm_parameters"] = self.get_utm_parameters() + return context + + class Meta: + verbose_name = "About Us Page" diff --git a/bedrock/mozorg/templates/mozorg/cms/about/about-us.html b/bedrock/mozorg/templates/mozorg/cms/about/about-us.html new file mode 100644 index 00000000000..f4747db5600 --- /dev/null +++ b/bedrock/mozorg/templates/mozorg/cms/about/about-us.html @@ -0,0 +1,37 @@ +{# + 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/. +#} + +{% extends "base-protocol-mozilla.html" %} + +{% block page_title %}{{ ftl('m24-about-page-title') }}{% endblock %} +{% block page_title_suffix %}{% endblock %} + +{% block page_desc %} + {{ ftl('m24-about-page-desc') }} +{% endblock %} + +{% block body_id %}about{% endblock %} + +{% block page_css %} + {{ css_bundle('m24-root') }} + {{ css_bundle('m24-base') }} + {{ css_bundle('m24-about') }} +{% endblock %} + +{% set utm_params = '?utm_source=www.mozilla.org&utm_medium=referral&utm_campaign=m24-about' %} + +{% block content %} +
+ {% include 'mozorg/about/includes/m24/intro.html'%} + {% include 'mozorg/about/includes/m24/manifesto.html'%} + + {# CMS managed content blocks #} + {% for block in page.content %} + {% include_block block %} + {% endfor %} + +
+{% endblock %} diff --git a/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_block.html b/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_block.html index 10c6bb0c3ac..dab57451f70 100644 --- a/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_block.html +++ b/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_block.html @@ -10,19 +10,13 @@
-
+

{{ value.heading }}

{{ value.body|richtext }}
-
{{ srcset_image(value.image, "width-1376", class="", sizes="1376px", alt=value.image_alt if value.image_alt else "") }}
diff --git a/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_gallery_block.html b/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_gallery_block.html new file mode 100644 index 00000000000..25dc16aaacf --- /dev/null +++ b/bedrock/mozorg/templates/mozorg/cms/blocks/showcase_gallery_block.html @@ -0,0 +1,72 @@ +{# + 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/. +#} + +{% set bg_color = value.settings.background_color %} +{% set anchor_id = value.settings.anchor_id|slugify if value.settings.anchor_id else "" %} + +{# Map image ratios to srcset_image fill specs #} +{% set ratio_fill_specs = { + "1:1": "fill-{375x375,432x432}", + "2:3": "fill-{230x345,360x540,432x648}" +} %} + +{# Map image ratios to dimensions for width/height attributes #} +{% set ratio_dimensions = { + "1:1": {"width": "432", "height": "432"}, + "2:3": {"width": "432", "height": "648"} +} %} + +{# Mobile images always use 1:1 ratio #} +{% set mobile_fill_spec = "fill-{375x375,432x432}" %} +{% set mobile_dimensions = {"width": "432", "height": "432"} %} + +
+

{{ value.heading }}

+
+ + {% for tile in value.tiles %} + {% set tile_alt = tile.image_alt|default("", true) %} + + {% set mobile_img = srcset_image(tile.image, mobile_fill_spec) %} + {% set desktop_img = srcset_image(tile.image, ratio_fill_specs["2:3"]) %} + {% set dimensions = ratio_dimensions["2:3"] %} + + {% set ns = namespace(mobile_srcset='', desktop_srcset='', desktop_src='') %} + {% for r in mobile_img.renditions %} + {% set ns.mobile_srcset = ns.mobile_srcset ~ (', ' if loop.index > 1 else '') ~ r.url ~ ' ' ~ r.width ~ 'w' %} + {% endfor %} + {% for r in desktop_img.renditions %} + {% if loop.first %} + {% set ns.desktop_src = r.url %} + {% endif %} + {% set ns.desktop_srcset = ns.desktop_srcset ~ (', ' if loop.index > 1 else '') ~ r.url ~ ' ' ~ r.width ~ 'w' %} + {% endfor %} + + + + {{ tile_alt }} + + + {% endfor %} + +
+

{{ value.body }}

+ +
diff --git a/bedrock/mozorg/tests/factories.py b/bedrock/mozorg/tests/factories.py index c5d5657a3b5..47667e32d24 100644 --- a/bedrock/mozorg/tests/factories.py +++ b/bedrock/mozorg/tests/factories.py @@ -326,3 +326,46 @@ class HomePageFactory(wagtail_factories.PageFactory): class Meta: model = models.HomePage + + +class ShowcaseGalleryImageBlockFactory(wagtail_factories.StructBlockFactory): + image = wagtail_factories.ImageChooserBlockFactory + image_alt = "" + + class Meta: + model = common.ShowcaseGalleryImageBlock + + +class ShowcaseGalleryBlockSettingsFactory(wagtail_factories.StructBlockFactory): + anchor_id = "" + background_color = "" + + class Meta: + model = common.ShowcaseGalleryBlockSettings + + +class ShowcaseGalleryBlockFactory(wagtail_factories.StructBlockFactory): + settings = factory.SubFactory(ShowcaseGalleryBlockSettingsFactory) + heading = "Working at Mozilla" + tiles = wagtail_factories.ListBlockFactory(ShowcaseGalleryImageBlockFactory) + body = "Join a team that believes the internet is for everyone." + cta_text = "See open roles" + cta_link = factory.SubFactory(LinkBlockFactory) + + class Meta: + model = common.ShowcaseGalleryBlock + + +class AboutUsPageFactory(wagtail_factories.PageFactory): + title = "Test About Us Page" + live = True + slug = "about-us" + + content = wagtail_factories.StreamFieldFactory( + { + "showcase_gallery_block": factory.SubFactory(ShowcaseGalleryBlockFactory), + } + ) + + class Meta: + model = models.AboutUsPage diff --git a/bedrock/mozorg/tests/test_blocks.py b/bedrock/mozorg/tests/test_blocks.py index 242b59040a6..d3415401956 100644 --- a/bedrock/mozorg/tests/test_blocks.py +++ b/bedrock/mozorg/tests/test_blocks.py @@ -17,6 +17,7 @@ from bedrock.mozorg.fixtures.base_fixtures import get_placeholder_image from bedrock.mozorg.fixtures.donate_fixtures import get_donate_test_page, get_donate_variants from bedrock.mozorg.fixtures.showcase_fixtures import get_showcase_test_page, get_showcase_variants +from bedrock.mozorg.fixtures.showcase_gallery_fixtures import get_showcase_gallery_test_page, get_showcase_gallery_variants from bedrock.mozorg.fixtures.springboard_fixtures import get_springboard_test_page, get_springboard_variants pytestmark = [pytest.mark.django_db] @@ -681,3 +682,186 @@ def test_showcase_block_new_window(minimal_site, rf, serving_method): # noqa: F assert cta_link.get("target") == "_blank", "Expected target='_blank'" assert "noopener" in cta_link.get("rel", []), "Expected 'noopener' in rel" assert "external" in cta_link.get("rel", []), "Expected 'external' in rel" + + +# ShowcaseGalleryBlock Tests + + +def assert_showcase_gallery_block_structure(careers_element: BeautifulSoup): + """Verify the showcase gallery block has the expected HTML structure. + + Args: + careers_element: BeautifulSoup element for the .m24-c-careers div + """ + # Check title exists and is h2 + title = careers_element.find(class_="m24-c-careers-title") + assert title is not None, "Missing .m24-c-careers-title element" + assert title.name == "h2", f"Expected h2 title, got {title.name}" + + # Check media container and pictures + media = careers_element.find(class_="m24-c-careers-media") + assert media is not None, "Missing .m24-c-careers-media element" + + pictures = media.find_all("picture") + assert len(pictures) > 0, "Expected at least one element in media" + + for picture in pictures: + assert picture.find("img") is not None, "Missing inside " + + # Check body text paragraph + body = careers_element.find(class_="m24-consider-cta-info") + assert body is not None, "Missing .m24-consider-cta-info element" + + # Check CTA container and link + cta_container = careers_element.find(class_="m24-c-careers-cta") + assert cta_container is not None, "Missing .m24-c-careers-cta element" + + cta_link = cta_container.find("a", class_="m24-c-cta") + assert cta_link is not None, "Missing .m24-c-cta link in CTA container" + + +def assert_showcase_gallery_block_content(careers_element: BeautifulSoup, variant_data: dict): + """Verify the showcase gallery block content matches the input data. + + Args: + careers_element: BeautifulSoup element for the .m24-c-careers div + variant_data: The block data dictionary used to create the block + """ + value = variant_data["value"] + + # Check heading text + title = careers_element.find(class_="m24-c-careers-title") + assert value["heading"] in title.get_text(), f"Heading text '{value['heading']}' not found" + + # Check number of pictures matches number of tiles + media = careers_element.find(class_="m24-c-careers-media") + pictures = media.find_all("picture") + assert len(pictures) == len(value["tiles"]), f"Expected {len(value['tiles'])} pictures, found {len(pictures)}" + + # Check body text + body = careers_element.find(class_="m24-consider-cta-info") + assert value["body"] in body.get_text(), f"Body text '{value['body']}' not found" + + # Check CTA text and href + cta_link = careers_element.find("a", class_="m24-c-cta") + assert cta_link is not None, "CTA link not found" + assert value["cta_text"] in cta_link.get_text(), f"CTA text '{value['cta_text']}' not found" + + expected_url = value["cta_link"]["custom_url"] + assert cta_link["href"].startswith(expected_url.rstrip("/")), f"Expected href to start with '{expected_url}', got '{cta_link['href']}'" + + assert "data-cta-text" in cta_link.attrs, "Missing data-cta-text attribute" + assert cta_link["data-cta-text"], "data-cta-text attribute is empty" + + +def assert_showcase_gallery_block_attributes(careers_element: BeautifulSoup, variant_data: dict): + """Verify the showcase gallery block wrapper has correct attributes. + + Args: + careers_element: BeautifulSoup element for the .m24-c-careers div + variant_data: The block data dictionary used to create the block + """ + value = variant_data["value"] + settings = value["settings"] + + # Check background color class if set + bg_color = settings["background_color"] + if bg_color: + assert bg_color in careers_element.get("class", []), f"Expected class '{bg_color}' not found" + + # Check anchor ID if set + anchor_id = settings["anchor_id"] + if anchor_id: + assert careers_element.get("id") == anchor_id, f"Expected id '{anchor_id}', got '{careers_element.get('id')}'" + + # Check new_window attributes on CTA + cta_link = careers_element.find("a", class_="m24-c-cta") + if value["cta_link"].get("new_window"): + assert cta_link.get("target") == "_blank", "Expected target='_blank' for new_window=True" + assert "noopener" in cta_link.get("rel", []), "Expected 'noopener' in rel for new_window=True" + assert "external" in cta_link.get("rel", []), "Expected 'external' in rel for new_window=True" + else: + assert cta_link.get("target") is None, "Expected no target attribute for new_window=False" + + +@pytest.mark.parametrize("serving_method", ("serve", "serve_preview")) +def test_showcase_gallery_block_renders(minimal_site, rf, serving_method): # noqa: F811 + """Test that ShowcaseGalleryBlock renders with correct structure.""" + placeholder_image = get_placeholder_image() + variants = get_showcase_gallery_variants(placeholder_image.id) + test_page = get_showcase_gallery_test_page() + + _relative_url = test_page.relative_url(minimal_site) + request = rf.get(_relative_url) + response = getattr(test_page, serving_method)(request) + + assert response.status_code == 200 + + soup = BeautifulSoup(response.content, "html.parser") + + careers_divs = soup.find_all("div", class_="m24-c-careers") + assert len(careers_divs) == len(variants), f"Expected {len(variants)} showcase gallery blocks, found {len(careers_divs)}" + + for careers_div in careers_divs: + assert_showcase_gallery_block_structure(careers_div) + + +@pytest.mark.parametrize("serving_method", ("serve", "serve_preview")) +def test_showcase_gallery_block_content(minimal_site, rf, serving_method): # noqa: F811 + """Test that ShowcaseGalleryBlock content matches input data.""" + placeholder_image = get_placeholder_image() + variants = get_showcase_gallery_variants(placeholder_image.id) + test_page = get_showcase_gallery_test_page() + + _relative_url = test_page.relative_url(minimal_site) + request = rf.get(_relative_url) + response = getattr(test_page, serving_method)(request) + + soup = BeautifulSoup(response.content, "html.parser") + careers_divs = soup.find_all("div", class_="m24-c-careers") + + for index, variant in enumerate(variants): + assert_showcase_gallery_block_content(careers_divs[index], variant) + + +@pytest.mark.parametrize("serving_method", ("serve", "serve_preview")) +def test_showcase_gallery_block_attributes(minimal_site, rf, serving_method): # noqa: F811 + """Test that ShowcaseGalleryBlock has correct background color and anchor ID.""" + placeholder_image = get_placeholder_image() + variants = get_showcase_gallery_variants(placeholder_image.id) + test_page = get_showcase_gallery_test_page() + + _relative_url = test_page.relative_url(minimal_site) + request = rf.get(_relative_url) + response = getattr(test_page, serving_method)(request) + + soup = BeautifulSoup(response.content, "html.parser") + careers_divs = soup.find_all("div", class_="m24-c-careers") + + for index, variant in enumerate(variants): + assert_showcase_gallery_block_attributes(careers_divs[index], variant) + + +@pytest.mark.parametrize("serving_method", ("serve", "serve_preview")) +def test_showcase_gallery_block_new_window(minimal_site, rf, serving_method): # noqa: F811 + """Test that new_window=True adds correct link attributes.""" + placeholder_image = get_placeholder_image() + variants = get_showcase_gallery_variants(placeholder_image.id) + test_page = get_showcase_gallery_test_page() + + _relative_url = test_page.relative_url(minimal_site) + request = rf.get(_relative_url) + response = getattr(test_page, serving_method)(request) + + soup = BeautifulSoup(response.content, "html.parser") + + new_window_variant = next(v for v in variants if v["value"]["cta_link"].get("new_window")) + expected_cta_text = new_window_variant["value"]["cta_text"] + + cta_links = soup.find_all("a", class_="m24-c-cta") + cta_link = next((link for link in cta_links if expected_cta_text in link.get_text()), None) + assert cta_link is not None, f"CTA link with text '{expected_cta_text}' not found" + + assert cta_link.get("target") == "_blank", "Expected target='_blank'" + assert "noopener" in cta_link.get("rel", []), "Expected 'noopener' in rel" + assert "external" in cta_link.get("rel", []), "Expected 'external' in rel" diff --git a/bedrock/mozorg/tests/test_models.py b/bedrock/mozorg/tests/test_models.py index 30abb184632..8776091127c 100644 --- a/bedrock/mozorg/tests/test_models.py +++ b/bedrock/mozorg/tests/test_models.py @@ -8,6 +8,7 @@ from wagtail.rich_text import RichText from bedrock.cms.tests.conftest import minimal_site # noqa: F401, F811 +from bedrock.mozorg import models from bedrock.mozorg.tests import factories pytestmark = [ @@ -429,3 +430,52 @@ def test_advertising_index_page_valid_navigation_anchor_reference_in_header( assert advertising_page.id is not None # Should not raise ValidationError advertising_page.clean() # No exception expected + + +# AboutUsPage Tests + + +@pytest.mark.parametrize("serving_method", ("serve", "serve_preview")) +def test_about_us_page(minimal_site, rf, serving_method): # noqa: F811 + root_page = minimal_site.root_page + + about_us_page = factories.AboutUsPageFactory( + parent=root_page, + content__0__showcase_gallery_block=factories.ShowcaseGalleryBlockFactory( + heading="Working at Mozilla", + body="Join a team that believes the internet is for everyone.", + cta_text="See open roles", + cta_link=factories.LinkBlockFactory( + link_to="custom_url", + custom_url="https://example.com/careers", + ), + ), + ) + about_us_page.save() + + _relative_url = about_us_page.relative_url(minimal_site) + assert _relative_url == "/en-US/about-us/" + request = rf.get(_relative_url) + + resp = getattr(about_us_page, serving_method)(request) + assert resp.status_code == 200 + page_content = resp.text + assert "Working at Mozilla" in page_content + assert "Join a team that believes the internet is for everyone." in page_content + assert "See open roles" in page_content + + +def test_about_us_page_utm_parameters(minimal_site): # noqa: F811 + root_page = minimal_site.root_page + about_us_page = factories.AboutUsPageFactory(parent=root_page, slug="about") + about_us_page.save() + + utm_params = about_us_page.get_utm_parameters() + + assert utm_params["utm_source"] == "www.mozilla.org" + assert utm_params["utm_medium"] == "referral" + assert utm_params["utm_campaign"] == "about" + + +def test_about_us_page_subpage_types(): + assert models.LeadershipPage in models.AboutUsPage.subpage_types diff --git a/bedrock/mozorg/urls.py b/bedrock/mozorg/urls.py index a5df52a6a4a..608be8804fc 100644 --- a/bedrock/mozorg/urls.py +++ b/bedrock/mozorg/urls.py @@ -14,14 +14,15 @@ from django.urls import path +from bedrock.cms.decorators import prefer_cms from bedrock.redirects.util import redirect from . import views from .util import page urlpatterns = [ - path("", views.HomeView.as_view(), name="mozorg.home"), - path("about/", views.AboutView.as_view(), name="mozorg.about.index"), + path("", prefer_cms(views.HomeView.as_view()), name="mozorg.home"), + path("about/", prefer_cms(views.AboutView.as_view()), name="mozorg.about.index"), page("about/manifesto/", "mozorg/about/manifesto.html", ftl_files=["mozorg/about/manifesto"]), page("about/manifesto/details/", "mozorg/about/manifesto-details.html", ftl_files=["mozorg/about/manifesto"]), page("account/", "mozorg/account.html", ftl_files=["firefox/accounts"]), diff --git a/bedrock/settings/base.py b/bedrock/settings/base.py index fbe792f8a37..64a8bbc7cca 100644 --- a/bedrock/settings/base.py +++ b/bedrock/settings/base.py @@ -2720,6 +2720,7 @@ def lazy_wagtail_langs(): "anonym.AnonymCaseStudyPage", "anonym.AnonymContactPage", "mozorg.HomePage", + "mozorg.AboutUsPage", "mozorg.LeadershipPage", "products.VPNResourceCenterDetailPage", "products.VPNResourceCenterIndexPage", diff --git a/bin/export-db-to-sqlite.sh b/bin/export-db-to-sqlite.sh index 9bbdd50b26d..0b44d02185a 100755 --- a/bin/export-db-to-sqlite.sh +++ b/bin/export-db-to-sqlite.sh @@ -176,6 +176,7 @@ python manage.py dumpdata \ mozorg.AdvertisingTwoColumnSubpage \ mozorg.ContentSubpage \ mozorg.HomePage \ + mozorg.AboutUsPage \ mozorg.ContactBannerSnippet \ mozorg.NotificationSnippet \ newsletter.Newsletter \