Esempio n. 1
0
class OpportunityPage(MiniSiteNameSpace):

    content_panels = Page.content_panels + [
        FieldPanel('header'),
        StreamFieldPanel('body'),
    ]

    subpage_types = [
        'OpportunityPage', 'RedirectingPage', 'PublicationPage', 'ArticlePage'
    ]

    translatable_fields = [
        # Promote tab fields
        TranslatableField('seo_title'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
        TranslatableField('header'),
        TranslatableField('body'),
    ]

    class Meta:
        verbose_name = "Default Page"
        verbose_name_plural = "Default pages"
class CampaignIndexPage(IndexPage):
    """
    The campaign index is specifically for campaign-related pages
    """

    subpage_types = [
        'BanneredCampaignPage', 'CampaignPage', 'DearInternetPage',
        'OpportunityPage', 'YoutubeRegretsPage', 'YoutubeRegretsReporterPage',
        'PublicationPage', 'ArticlePage'
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields from IndexPage
        TranslatableField('title'),
        TranslatableField('intro'),
        TranslatableField('header'),
        SynchronizedField('page_size'),
    ]

    template = 'wagtailpages/index_page.html'

    def get_context(self, request):
        # bootstrap the render context
        context = super().get_context(request)
        entries = self.get_all_entries().not_type(PublicationPage)
        context['entries'] = entries[0:self.page_size]
        # Which pagetype to exclude during the "load more" ajax request: PublicationPage
        context['exclude_pagetype'] = 'publicationpage'
        return context
Esempio n. 3
0
class TestPage(Page):
    test_charfield = models.CharField(__("char field"),
                                      max_length=255,
                                      blank=True)
    test_textfield = models.TextField(blank=True)
    test_emailfield = models.EmailField(blank=True)
    test_slugfield = models.SlugField(blank=True)
    test_urlfield = models.URLField(blank=True)

    test_richtextfield = RichTextField(blank=True)
    test_streamfield = StreamField(TestStreamBlock, blank=True)

    test_snippet = models.ForeignKey(TestSnippet,
                                     null=True,
                                     blank=True,
                                     on_delete=models.SET_NULL)

    test_customfield = TestCustomField(blank=True)

    test_synchronized_charfield = models.CharField(max_length=255, blank=True)
    test_synchronized_textfield = models.TextField(blank=True)
    test_synchronized_emailfield = models.EmailField(blank=True)
    test_synchronized_slugfield = models.SlugField(blank=True)
    test_synchronized_urlfield = models.URLField(blank=True)

    test_synchronized_richtextfield = RichTextField(blank=True)
    test_synchronized_streamfield = StreamField(TestStreamBlock, blank=True)

    test_synchronized_snippet = models.ForeignKey(TestSnippet,
                                                  null=True,
                                                  blank=True,
                                                  on_delete=models.SET_NULL,
                                                  related_name="+")

    test_synchronized_customfield = TestCustomField(blank=True)

    translatable_fields = [
        TranslatableField("test_charfield"),
        TranslatableField("test_textfield"),
        TranslatableField("test_emailfield"),
        TranslatableField("test_slugfield"),
        TranslatableField("test_urlfield"),
        TranslatableField("test_richtextfield"),
        TranslatableField("test_streamfield"),
        TranslatableField("test_snippet"),
        TranslatableField("test_childobjects"),
        TranslatableField("test_customfield"),
        SynchronizedField("test_synchronized_charfield"),
        SynchronizedField("test_synchronized_textfield"),
        SynchronizedField("test_synchronized_emailfield"),
        SynchronizedField("test_synchronized_slugfield"),
        SynchronizedField("test_synchronized_urlfield"),
        SynchronizedField("test_synchronized_richtextfield"),
        SynchronizedField("test_synchronized_streamfield"),
        SynchronizedField("test_synchronized_snippet"),
        SynchronizedField("test_synchronized_childobjects"),
        SynchronizedField("test_synchronized_customfield"),
    ]
Esempio n. 4
0
class TestModel(TranslatableMixin):
    title = models.CharField(max_length=255)
    test_charfield = models.CharField(max_length=255, blank=True)
    test_textfield = models.TextField(blank=True)
    test_emailfield = models.EmailField(blank=True)

    translatable_fields = [
        TranslatableField("test_charfield"),
        TranslatableField("test_textfield"),
        TranslatableField("test_emailfield"),
    ]
Esempio n. 5
0
class CampaignPage(DonationPage):
    template = 'pages/core/campaign_page.html'
    parent_page_types = ['core.LandingPage', 'core.CampaignPage']
    subpage_types = ['core.CampaignPage']

    submit_to_pontoon_on_publish = False

    hero_image = models.ForeignKey(
        'wagtailimages.Image',
        models.PROTECT,
        related_name='+',
    )
    lead_text = models.CharField(max_length=800)
    intro = RichTextField()

    content_panels = Page.content_panels + [
        FieldPanel('project'),
        ImageChooserPanel('hero_image'),
        FieldPanel('lead_text'),
        FieldPanel('intro'),
        InlinePanel('donation_amounts', label='Donation amount overrides'),
    ]

    translatable_fields = [
        TranslatableField('title'),
        TranslatableField('seo_title'),
        TranslatableField('search_description'),
        SynchronizedField('project'),
        SynchronizedField('campaign_id'),
        SynchronizedField('hero_image'),
        TranslatableField('lead_text'),
        TranslatableField('intro'),
    ]

    @classmethod
    def amount_stream_to_list(cls, stream):
        return [Decimal(child.value) for child in stream]

    @classmethod
    def get_presets(cls, override):
        return {
            'single': cls.amount_stream_to_list(override.single_options),
            'monthly': cls.amount_stream_to_list(override.monthly_options),
        }

    @cached_property
    def currencies(self):
        currencies = super().currencies
        # Apply overrides for preset options
        for override in self.donation_amounts.all():
            currencies[override.currency]['presets'] = self.get_presets(
                override)
        return currencies
Esempio n. 6
0
class DonationModal(TranslatableMixin, models.Model):
    name = models.CharField(
        default='',
        max_length=100,
        help_text='Identify this component for other editors',
    )

    header = models.CharField(
        max_length=500,
        help_text='Donation header',
        default="Thanks for signing! While you're here, we need your help.",
    )

    body = models.TextField(
        help_text='Donation text',
        default='Mozilla is a nonprofit organization fighting for '
        'a healthy internet, where privacy is included by '
        'design and you have more control over your personal '
        'information. We depend on contributions from people '
        'like you to carry out this work. Can you donate today?')

    donate_text = models.CharField(
        max_length=150,
        help_text='Donate button label',
        default="Yes, I'll chip in",
    )

    dismiss_text = models.CharField(
        max_length=150,
        help_text='Dismiss button label',
        default="No thanks",
    )

    translatable_fields = [
        TranslatableField('header'),
        TranslatableField('body'),
        TranslatableField('donate_text'),
        TranslatableField('dismiss_text'),
    ]

    def to_simple_dict(self):
        keys = ['name', 'header', 'body', 'donate_text', 'dismiss_text']
        values = map(lambda k: getattr(self, k), keys)
        return dict(zip(keys, values))

    def __str__(self):
        return self.name

    class Meta(TranslatableMixin.Meta):
        verbose_name_plural = 'Donation CTA'
Esempio n. 7
0
class TestNonParentalChildObject(TranslatableMixin, Orderable):
    page = models.ForeignKey(TestPage,
                             on_delete=models.CASCADE,
                             related_name="test_nonparentalchildobjects")
    field = models.TextField()

    translatable_fields = [TranslatableField("field")]
Esempio n. 8
0
class TestChildObject(TranslatableMixin, Orderable):
    page = ParentalKey(TestPage, related_name="test_childobjects")
    field = models.TextField()

    translatable_fields = [TranslatableField("field")]

    class Meta(TranslatableMixin.Meta, Orderable.Meta):
        pass
Esempio n. 9
0
class TestModelWithInvalidForeignKey(TranslatableMixin, models.Model):
    fk = models.ForeignKey('wagtailcore.Site', on_delete=models.CASCADE)

    # This should raise an error as the model being pointed to is not
    # translatable!
    translatable_fields = [
        TranslatableField('fk'),
    ]
Esempio n. 10
0
class LandingPage(TranslatablePageRoutingMixin, DonationPage):
    template = 'pages/core/landing_page.html'

    # Only allow creating landing pages at the root level
    parent_page_types = ['wagtailcore.Page']

    subpage_types = [
        'core.CampaignPage',
        'core.ContentPage',
        'core.ContributorSupportPage',
    ]

    featured_image = models.ForeignKey(
        'wagtailimages.Image',
        models.PROTECT,
        related_name='+',
    )
    intro = RichTextField()

    content_panels = Page.content_panels + [
        FieldPanel('project'),
        ImageChooserPanel('featured_image'),
        FieldPanel('intro'),
    ]

    translatable_fields = [
        TranslatableField('title'),
        TranslatableField('seo_title'),
        TranslatableField('search_description'),
        SynchronizedField('project'),
        SynchronizedField('campaign_id'),
        SynchronizedField('featured_image'),
        TranslatableField('intro'),
    ]

    def save(self, *args, **kwargs):
        # This slug isn't used anywhere but it does need to be unique for each language
        language_code = self.locale.language.code.lower()
        if language_code == 'en-us':
            # Needs to be something nice as translators will see it
            self.slug = 'mozilla-donate'
        else:
            self.slug = 'mozilla-donate-' + language_code

        super().save(*args, **kwargs)
Esempio n. 11
0
class ContributorSupportPage(TranslatablePageMixin, Page):
    template = 'pages/core/contributor_support_page.html'
    parent_page_types = ['core.LandingPage']

    # This page does not have subpages

    translatable_fields = [
        TranslatableField('title'),
        TranslatableField('seo_title'),
        TranslatableField('search_description'),
    ]

    def get_context(self, request):
        ctx = super().get_context(request)
        ctx.update({
            'orgid': settings.SALESFORCE_ORGID,
        })
        return ctx
Esempio n. 12
0
class Signup(TranslatableMixin, CTA):
    campaign_id = models.CharField(
        max_length=20,
        help_text='Which campaign identifier should this petition be tied to?',
        null=True,
        blank=True,
    )

    ask_name = models.BooleanField(
        help_text='Check this box to show (optional) name fields',
        default=False,
    )

    translatable_fields = [
        # Fields from the CTA model
        TranslatableField('header'),
        TranslatableField('description'),
    ]

    class Meta(TranslatableMixin.Meta):
        verbose_name = 'signup snippet'
Esempio n. 13
0
class ContentPage(TranslatablePageMixin, Page):
    template = 'pages/core/content_page.html'
    parent_page_types = ['core.LandingPage']
    subpage_types = ['core.ContentPage']

    call_to_action_text = models.CharField(max_length=255, blank=True)
    call_to_action_url = models.URLField(blank=True)

    body = StreamField(ContentBlock)

    content_panels = Page.content_panels + [
        FieldPanel('call_to_action_text'),
        FieldPanel('call_to_action_url'),
        StreamFieldPanel('body'),
    ]

    translatable_fields = [
        TranslatableField('title'),
        TranslatableField('seo_title'),
        TranslatableField('search_description'),
        TranslatableField('call_to_action_text'),
        SynchronizedField('call_to_action_url'),
        TranslatableField('body'),
    ]
class YoutubeRegrets2021Page(FoundationMetadataPageMixin, Page):

    template = 'wagtailpages/pages/youtube-regrets-2021/youtube_regrets_2021.html'
    max_count = 1
    zen_nav = True

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
    ]

    def get_context(self, request):
        context = super().get_context(request)
        return set_main_site_nav_information(self, context, 'Homepage')

    class Meta:
        verbose_name = "YouTube Regrets 2021 Page"
        verbose_name_plural = "YouTube Regrets 2021 Pages"
Esempio n. 15
0
class CampaignPage(MiniSiteNameSpace):
    """
    these pages come with sign-a-petition CTAs
    """
    cta = models.ForeignKey(
        'Petition',
        related_name='page',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text='Choose existing or create new sign-up form')

    def get_donation_modal_json(self):
        modals = self.donation_modals.all()
        # This is where we can do server-side A/B testing,
        # by either sending all modals down the pipe, or
        # selectively only sending a single one based on
        # things like geolocation, time of day, etc.
        modals_json = [m.to_simple_dict() for m in modals]
        return json.dumps(modals_json)

    content_panels = Page.content_panels + [
        FieldPanel('header'),
        SnippetChooserPanel('cta'),
        InlinePanel('donation_modals', label='Donation Modal', max_num=4),
        StreamFieldPanel('body'),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('cta'),
        TranslatableField('title'),
        TranslatableField('header'),
        SynchronizedField('narrowed_page_content'),
        SynchronizedField('zen_nav'),
        TranslatableField('body'),
        TranslatableField('donation_modals'),
    ]

    subpage_types = [
        'CampaignPage', 'RedirectingPage', 'PublicationPage', 'ArticlePage'
    ]
class YoutubeRegretsReporterPage(FoundationMetadataPageMixin, Page):
    headline = models.CharField(
        max_length=500,
        help_text='Page headline',
        blank=True,
    )

    intro_text = StreamField([
        ('text', blocks.CharBlock()),
    ])

    intro_images = StreamField([
        ('image', customblocks.ImageBlock()),
    ])

    content_panels = Page.content_panels + [
        FieldPanel('headline'),
        StreamFieldPanel('intro_text'),
        StreamFieldPanel('intro_images'),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
        TranslatableField('headline'),
        TranslatableField('intro_text'),
        TranslatableField('intro_images'),
    ]

    zen_nav = True

    def get_context(self, request):
        context = super().get_context(request)
        return set_main_site_nav_information(self, context, 'Homepage')

    template = 'wagtailpages/pages/youtube_regrets_reporter_page.html'
Esempio n. 17
0
class TestOverrideTranslatableFieldsPage(TestGenerateTranslatableFieldsPage):
    override_translatable_fields = [
        SynchronizedField('test_charfield'),
        TranslatableField('test_emailfield'),
    ]
Esempio n. 18
0
class TestPage(Page):
    test_charfield = models.CharField(gettext_lazy("char field"),
                                      max_length=255,
                                      blank=True,
                                      null=True,
                                      default='')
    test_textfield = models.TextField(blank=True)
    test_emailfield = models.EmailField(blank=True)
    test_slugfield = models.SlugField(blank=True)
    test_urlfield = models.URLField(blank=True)

    test_richtextfield = RichTextField(blank=True)
    test_streamfield = StreamField(TestStreamBlock, blank=True)

    test_snippet = models.ForeignKey(TestSnippet,
                                     null=True,
                                     blank=True,
                                     on_delete=models.SET_NULL)

    test_customfield = TestCustomField(blank=True)

    test_synchronized_charfield = models.CharField(max_length=255, blank=True)
    test_synchronized_textfield = models.TextField(blank=True)
    test_synchronized_emailfield = models.EmailField(blank=True)
    test_synchronized_slugfield = models.SlugField(blank=True)
    test_synchronized_urlfield = models.URLField(blank=True)

    test_synchronized_richtextfield = RichTextField(blank=True)
    test_synchronized_streamfield = StreamField(TestStreamBlock, blank=True)

    test_synchronized_image = models.ForeignKey('wagtailimages.Image',
                                                null=True,
                                                blank=True,
                                                on_delete=models.SET_NULL,
                                                related_name="+")
    test_synchronized_document = models.ForeignKey('wagtaildocs.Document',
                                                   null=True,
                                                   blank=True,
                                                   on_delete=models.SET_NULL,
                                                   related_name="+")
    test_synchronized_snippet = models.ForeignKey(TestSnippet,
                                                  null=True,
                                                  blank=True,
                                                  on_delete=models.SET_NULL,
                                                  related_name="+")

    test_page = models.ForeignKey(Page,
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL,
                                  related_name="+")

    test_page_specific_type = models.ForeignKey('TestHomePage',
                                                null=True,
                                                blank=True,
                                                on_delete=models.SET_NULL,
                                                related_name="+")

    test_page_with_restricted_types = models.ForeignKey(
        Page,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+")

    test_synchronized_customfield = TestCustomField(blank=True)

    translatable_fields = [
        TranslatableField("test_charfield"),
        TranslatableField("test_textfield"),
        TranslatableField("test_emailfield"),
        TranslatableField("test_slugfield"),
        TranslatableField("test_urlfield"),
        TranslatableField("test_richtextfield"),
        TranslatableField("test_streamfield"),
        TranslatableField("test_snippet"),
        TranslatableField("test_childobjects"),
        TranslatableField("test_customfield"),
        SynchronizedField("test_synchronized_charfield"),
        SynchronizedField("test_synchronized_textfield"),
        SynchronizedField("test_synchronized_emailfield"),
        SynchronizedField("test_synchronized_slugfield"),
        SynchronizedField("test_synchronized_urlfield"),
        SynchronizedField("test_synchronized_richtextfield"),
        SynchronizedField("test_synchronized_streamfield"),
        SynchronizedField("test_synchronized_image"),
        SynchronizedField("test_synchronized_document"),
        SynchronizedField("test_synchronized_snippet"),
        SynchronizedField("test_synchronized_childobjects"),
        SynchronizedField('test_page'),
        SynchronizedField('test_page_specific_type'),
        SynchronizedField('test_page_with_restricted_types'),
        SynchronizedField("test_synchronized_customfield"),
    ]

    content_panels = Page.content_panels + [
        FieldPanel("test_charfield"),
        FieldPanel("test_textfield"),
        FieldPanel("test_emailfield"),
        FieldPanel("test_slugfield"),
        FieldPanel("test_urlfield"),
        FieldPanel("test_richtextfield"),
        FieldPanel("test_streamfield"),
        FieldPanel("test_snippet"),
        InlinePanel("test_childobjects"),
        FieldPanel("test_customfield"),
        FieldPanel("test_synchronized_charfield"),
        FieldPanel("test_synchronized_textfield"),
        FieldPanel("test_synchronized_emailfield"),
        FieldPanel("test_synchronized_slugfield"),
        FieldPanel("test_synchronized_urlfield"),
        FieldPanel("test_synchronized_richtextfield"),
        FieldPanel("test_synchronized_streamfield"),
        FieldPanel("test_synchronized_image"),
        FieldPanel("test_synchronized_document"),
        FieldPanel("test_synchronized_snippet"),
        InlinePanel("test_synchronized_childobjects"),
        PageChooserPanel('test_page'),
        PageChooserPanel('test_page_specific_type'),
        PageChooserPanel('test_page_with_restricted_types', [
            'wagtail_localize_test.TestHomePage',
            'wagtail_localize_test.TestPage'
        ]),
        FieldPanel("test_synchronized_customfield"),
    ]
class Highlight(TranslatableMixin, SortableMixin):
    """
    An data type to highlight things like pulse
    projects, custom pages, etc
    Especially on the homepage under "Get Involved"
    """
    title = models.CharField(
        max_length=300,
        help_text='Title of the higlight',
    )
    description = models.TextField(
        max_length=5000,
        help_text='Description of the higlight',
    )
    link_label = models.CharField(
        max_length=300,
        help_text='Text to show that links to this higlight\'s '
        'details page',
    )
    link_url = models.URLField(
        max_length=2048,
        help_text='Link to this higlight\'s details page',
    )
    image = models.ForeignKey(
        'wagtailimages.Image',
        on_delete=models.SET_NULL,
        blank=False,
        null=True,
        related_name='+',
    )
    footer = RichTextField(
        "footer",
        help_text="Content to appear after description (view more projects "
        "link or something similar)",
        null=True,
    )
    publish_after = models.DateTimeField(
        help_text='Make this highlight visible only '
        'after this date and time (UTC)',
        null=True,
    )
    expires = models.DateTimeField(
        help_text='Hide this highlight after this date and time (UTC)',
        default=None,
        null=True,
        blank=True,
    )
    order = models.PositiveIntegerField(
        default=0,
        editable=False,
        db_index=True,
    )

    panels = [
        FieldPanel("title"),
        FieldPanel("description"),
        FieldPanel("link_label"),
        FieldPanel("link_url"),
        ImageChooserPanel("image"),
        FieldPanel("footer"),
        FieldPanel("publish_after"),
        FieldPanel("expires"),
    ]

    translatable_fields = [
        TranslatableField('title'),
        TranslatableField('description'),
        TranslatableField('link_label'),
        TranslatableField('footer'),
    ]

    objects = HighlightQuerySet.as_manager()

    class Meta(TranslatableMixin.Meta):
        verbose_name_plural = 'highlights'
        ordering = ('order', )

    def __str__(self):
        return str(self.title)
class ArticlePage(FoundationMetadataPageMixin, Page):

    """

    Articles can belong to any page in the Wagtail Tree.
    An ArticlePage can have no children
    If not a child of a Publication Page, page nav at bottom of page
    and breadcrumbs will not render.
    """
    subpage_types = []
    body = StreamField(article_fields)

    toc_thumbnail_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Table of Content Thumbnail',
        help_text='Thumbnail image to show on table of content. Use square image of 320×320 pixels or larger.',
    )

    hero_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Publication Hero Image',
    )

    subtitle = models.CharField(
        blank=True,
        max_length=250,
    )

    secondary_subtitle = models.CharField(
        blank=True,
        max_length=250,
    )

    publication_date = models.DateField("Publication date", null=True, blank=True)

    article_file = models.ForeignKey(
        'wagtaildocs.Document',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
    )

    show_side_share_buttons = models.BooleanField(
        default=True,
        help_text="Show social share buttons on the side"
    )

    content_panels = [
        FieldPanel(
            "title",
            classname="full title",
            widget=TitleWidget(attrs={"class": "max-length-warning", "data-max-length": 60})
        ),
        MultiFieldPanel([
            InlinePanel("authors", label="Author", min_num=0)
        ], heading="Author(s)"),
        MultiFieldPanel([
            ImageChooserPanel("toc_thumbnail_image"),
        ], heading="Table of Content Thumbnail"),
        MultiFieldPanel([
            ImageChooserPanel("hero_image"),
            FieldPanel('subtitle'),
            FieldPanel('secondary_subtitle'),
            FieldPanel('publication_date'),
            DocumentChooserPanel('article_file'),
        ], heading="Hero"),
        FieldPanel('show_side_share_buttons'),
        StreamFieldPanel('body'),
        InlinePanel("footnotes", label="Footnotes"),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
        SynchronizedField('toc_thumbnail_image'),
        SynchronizedField('hero_image'),
        TranslatableField('subtitle'),
        SynchronizedField('article_file'),
        TranslatableField('body'),
        TranslatableField('footnotes'),
    ]

    @property
    def is_publication_article(self):
        parent = self.get_parent().specific
        return parent.__class__ is PublicationPage

    @property
    def next_page(self):
        """
        Get the next page for a publication. Details below:

        Check the parent page type. If the parent page type is a "Chapter Page",
        then look for siblings of `this` page. If no next sibling can be found
        look for the parent page next sibling. And if that cannot be found,
        return the Chapter Page's parent (Publication Page).
        Otherwise if the parent page is a Publication page: look for the next sibling,
        if there is no next sibling page, return this pages' parent.
        """

        parent = self.get_parent().specific
        next_page = self.get_siblings().filter(path__gt=self.path, live=True).first()
        if parent.is_chapter_page:
            # if there is no next page look for the next chapter
            if not next_page:
                next_page = parent.get_siblings().filter(path__gt=self.path, live=True).first()
                # if there is no next chapter return to the parent.get_parent()
                if not next_page:
                    next_page = parent.get_parent()
        else:
            # Parent is a PublicationPage, not a chapter page
            # if there is no next page, return the parent
            if not next_page:
                next_page = parent

        return next_page

    @property
    def prev_page(self):
        """
        Get the previous page for a publication. Details below:

        Check the parent page type. If the parent page type is a "Chapter Page",
        then look for siblings of `this` page. If no previous sibling can be found
        look for the parent page previous sibling. And if that cannot be found,
        return the Chapter Page's parent (Publication Page).
        Otherwise if the parent page is a Publication page: look for the previous sibling,
        if there is no previous sibling page, return this pages' parent.
        """

        parent = self.get_parent().specific
        prev_page = self.get_siblings().filter(path__lt=self.path, live=True).reverse().first()
        if parent.is_chapter_page:
            # look for the previous page in this chapter
            # if there is no previous page look for the previous chapter
            if not prev_page:
                prev_page = parent.get_siblings().filter(path__lt=self.path, live=True).reverse().first()
                # if there is no previous chapter return to the parent.get_parent()
                if not prev_page:
                    prev_page = parent.get_parent()
        else:
            # Parent is a PublicationPage, not a chapter page
            # look for the previous page in this publication
            # if there is no previous page, return the parent
            if not prev_page:
                prev_page = parent

        return prev_page

    def breadcrumb_list(self):
        """
        Get all the parent PublicationPages and return a QuerySet
        """
        return Page.objects.ancestor_of(self).type(PublicationPage).live()

    @property
    def zen_nav(self):
        return True

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        # Add get_titles to the page context. This is in get_context() because
        # we need access to the `request` object
        # menu_items is required for zen_nav in the templates
        context['get_titles'] = get_plaintext_titles(request, self.body, "content")
        return set_main_site_nav_information(self, context, 'Homepage')
Esempio n. 21
0
class DearInternetPage(FoundationMetadataPageMixin, Page):
    intro_texts = StreamField([('intro_text',
                                blocks.RichTextBlock(features=[
                                    'bold',
                                    'italic',
                                    'link',
                                ]))], )

    letters_section_heading = models.CharField(
        max_length=300,
        default='Stories from around the world',
    )

    letters = StreamField([
        ('letter', customblocks.DearInternetLetterBlock()),
    ])

    cta = models.CharField(max_length=500, )

    cta_button_text = models.CharField(max_length=100, )

    cta_button_link = models.URLField()

    content_panels = Page.content_panels + [
        StreamFieldPanel('intro_texts'),
        FieldPanel('letters_section_heading'),
        StreamFieldPanel('letters'),
        MultiFieldPanel(
            [
                FieldPanel('cta'),
                FieldPanel('cta_button_text'),
                FieldPanel('cta_button_link'),
            ],
            heading='CTA',
        ),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
        TranslatableField('intro_texts'),
        TranslatableField('letters_section_heading'),
        TranslatableField('letters'),
        TranslatableField('cta'),
        TranslatableField('cta_button_text'),
        SynchronizedField('cta_button_link'),
    ]

    zen_nav = True

    def get_context(self, request):
        context = super().get_context(request)
        return set_main_site_nav_information(self, context, 'Homepage')

    template = 'wagtailpages/pages/dear_internet_page.html'
Esempio n. 22
0
class TestSnippet(TranslatableMixin, models.Model):
    field = models.TextField()

    translatable_fields = [TranslatableField("field")]
Esempio n. 23
0
class TestSynchronizedChildObject(Orderable):
    page = ParentalKey(TestPage, related_name="test_synchronized_childobjects")
    field = models.TextField()

    translatable_fields = [TranslatableField("field")]
class MozfestHomepage(MozfestPrimaryPage):
    """
    MozFest Homepage

    'banner_video_type' determines what version of banner design the page should load
    """

    #  this tells the templates to load a hardcoded, pre-defined video in the banner background
    banner_video_type = "hardcoded"

    cta_button_label = models.CharField(
        max_length=250,
        blank=True,
        help_text='Label text for the CTA button in the primary nav bar',
    )

    cta_button_destination = models.CharField(
        max_length=2048,
        blank=True,
        help_text='The URL for the page that the CTA button in the primary nav bar should redirect to.'
                  'E.g., /proposals, https://example.com/external-link',
    )

    banner_heading = models.CharField(
        max_length=250,
        blank=True,
        help_text='A banner heading specific to the homepage'
    )

    banner_guide_text = models.CharField(
        max_length=1000,
        blank=True,
        help_text='A banner paragraph specific to the homepage'
    )

    banner_video_url = models.URLField(
        max_length=2048,
        blank=True,
        help_text='The video to play when users click "watch video"'
    )

    subpage_types = [
        'MozfestPrimaryPage',
        'MozfestHomepage',
    ]

    # Put everything above the body
    parent_panels = MozfestPrimaryPage.content_panels
    panel_count = len(parent_panels)
    n = panel_count - 1

    all_panels = parent_panels[:n] + [
        FieldPanel('cta_button_label'),
        FieldPanel('cta_button_destination'),
        FieldPanel('banner_heading'),
        FieldPanel('banner_guide_text'),
        FieldPanel('banner_video_url'),
    ] + parent_panels[n:]

    if banner_video_type == "hardcoded":
        # Hide all the panels that aren't relevant for the video banner version of the MozFest Homepage
        content_panels = [
            field for field in all_panels
            if field.field_name not in
            ['banner', 'header', 'intro', 'banner_guide_text', 'banner_video_url']
        ]
    else:
        content_panels = all_panels

    # Because we inherit from PrimaryPage, but the "use_wide_template" property does nothing
    # we should hide it and make sure we use the right template
    settings_panels = Page.settings_panels

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
        TranslatableField('cta_button_label'),
        SynchronizedField('cta_button_destination'),
        TranslatableField('banner_heading'),
        TranslatableField('banner_guide_text'),
        SynchronizedField('banner_video_url'),
        TranslatableField('title'),
        TranslatableField('search_description'),
        TranslatableField('search_image'),
        TranslatableField('signup'),
        TranslatableField('body'),
        TranslatableField('footnotes'),
    ]

    def get_context(self, request):
        context = super().get_context(request)
        context['banner_video_type'] = self.specific.banner_video_type

        return context

    def get_template(self, request):
        return 'mozfest/mozfest_homepage.html'
Esempio n. 25
0
class BanneredCampaignPage(PrimaryPage):
    """
    title, header, intro, and body are inherited from PrimaryPage
    """

    # Note that this is a different related_name, as the `page`
    # name is already taken as back-referenced to CampaignPage.
    cta = models.ForeignKey(
        'Petition',
        related_name='bcpage',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text='Choose an existing, or create a new, pettition form')

    signup = models.ForeignKey(
        'Signup',
        related_name='bcpage',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text='Choose an existing, or create a new, sign-up form')

    tags = ClusterTaggableManager(through=BanneredCampaignTag, blank=True)

    panel_count = len(PrimaryPage.content_panels)
    n = panel_count - 1

    content_panels = PrimaryPage.content_panels[:n] + [
        SnippetChooserPanel('cta'),
        SnippetChooserPanel('signup'),
    ] + PrimaryPage.content_panels[n:]

    promote_panels = FoundationMetadataPageMixin.promote_panels + [
        FieldPanel('tags'),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('header'),
        TranslatableField('intro'),
        TranslatableField('body'),
        TranslatableField("title"),
        SynchronizedField("banner"),
        SynchronizedField("narrowed_page_content"),
        SynchronizedField("zen_nav"),
        TranslatableField("cta"),
        TranslatableField("signup"),
    ]

    subpage_types = [
        'BanneredCampaignPage', 'RedirectingPage', 'PublicationPage',
        'OpportunityPage', 'ArticlePage'
    ]

    show_in_menus_default = True

    def get_context(self, request):
        context = super().get_context(request)
        context['related_posts'] = get_content_related_by_tag(self)
        return get_page_tree_information(self, context)

    class Meta:
        verbose_name = "Banner Page"
        verbose_name_plural = "Banner pages"
    def test(self):
        translatable_fields = get_translatable_fields(
            TestOverrideTranslatableFieldsPage)

        self.assertEqual(
            translatable_fields,
            [
                TranslatableField("title"),
                TranslatableField("slug"),
                TranslatableField("seo_title"),
                SynchronizedField("show_in_menus"),
                TranslatableField("search_description"),
                SynchronizedField("test_charfield"),  # Overriden!
                SynchronizedField("test_charfield_with_choices"),
                TranslatableField("test_textfield"),
                TranslatableField("test_emailfield"),  # Overriden!
                TranslatableField("test_slugfield"),
                SynchronizedField("test_urlfield"),
                TranslatableField("test_richtextfield"),
                TranslatableField("test_streamfield"),
                TranslatableField("test_snippet"),
                SynchronizedField("test_nontranslatablesnippet"),
                TranslatableField("test_customfield"),
                TranslatableField("test_translatable_childobjects"),
                SynchronizedField("test_nontranslatable_childobjects"),
            ],
        )
class PublicationPage(FoundationMetadataPageMixin, Page):
    """
    This is the root page of a publication.

    From here the user can browse to the various sections (called chapters).
    It will have information on the publication, its authors, and metadata from it's children

    Publications are collections of Articles
    Publications can also be broken down into Chapters, which are really just child publication pages
    Each of those Chapters may have several Articles
    An Article can only belong to one Chapter/Publication Page
    """

    subpage_types = ['ArticlePage', 'PublicationPage']

    toc_thumbnail_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='toc_thumbnail_image',
        verbose_name='Table of Content Thumbnail',
        help_text=
        'Thumbnail image to show on table of content. Use square image of 320×320 pixels or larger.',
    )

    hero_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='publication_hero_image',
        verbose_name='Publication Hero Image',
    )
    subtitle = models.CharField(
        blank=True,
        max_length=250,
    )
    secondary_subtitle = models.CharField(
        blank=True,
        max_length=250,
    )
    publication_date = models.DateField("Publication date",
                                        null=True,
                                        blank=True)
    publication_file = models.ForeignKey(
        'wagtaildocs.Document',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
    )
    additional_author_copy = models.CharField(
        help_text="Example: with contributing authors",
        max_length=100,
        blank=True,
    )
    intro_notes = RichTextField(blank=True,
                                features=['link', 'bold', 'italic', 'h4'])
    notes = RichTextField(
        blank=True, features=['link', 'bold', 'italic', 'h4', 'ol', 'ul'])
    contents_title = models.CharField(
        blank=True,
        default="Table of Contents",
        max_length=250,
    )
    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel('subtitle'),
                FieldPanel('secondary_subtitle'),
                FieldPanel('publication_date'),
                ImageChooserPanel('toc_thumbnail_image'),
                ImageChooserPanel('hero_image'),
                DocumentChooserPanel('publication_file'),
                InlinePanel('authors', label='Author'),
                FieldPanel('additional_author_copy'),
            ],
            heading='Hero',
        ),
        FieldPanel('intro_notes'),
        FieldPanel('contents_title'),
        FieldPanel('notes'),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField("title"),
        TranslatableField("subtitle"),
        TranslatableField('secondary_subtitle'),
        SynchronizedField('toc_thumbnail_image'),
        SynchronizedField('hero_image'),
        SynchronizedField('publication_date'),
        SynchronizedField('publication_file'),
        TranslatableField('additional_author_copy'),
        TranslatableField('intro_notes'),
        TranslatableField('contents_title'),
        TranslatableField('notes'),
    ]

    @property
    def is_publication_page(self):
        """
        Returning true to let publication_hero.html to show breadcrumbs
        """
        return True

    @property
    def is_chapter_page(self):
        """
        A PublicationPage nested under a PublicationPage is considered to be a
        "ChapterPage". The templates used very similar logic and structure, and
        all the fields are the same.
        """
        parent = self.get_parent().specific
        return parent.__class__ is PublicationPage

    @property
    def next_page(self):
        """
        Only applies to Chapter Publication (sub-Publication Pages).
        Returns a Page object or None.
        """
        next_page = self.get_parent()
        if self.is_chapter_page:
            sibling = self.get_siblings().filter(path__gt=self.path,
                                                 live=True).first()
            if sibling:
                # If there is no more chapters. Return the parent page.
                next_page = sibling
        return next_page

    @property
    def prev_page(self):
        """
        Only applies to Chapter Publication (sub-Publication Pages).
        Returns a Page object or None.
        """
        prev_page = self.get_parent()
        if self.is_chapter_page:
            sibling = self.get_siblings().filter(path__lt=self.path,
                                                 live=True).reverse().first()
            if sibling:
                # If there is no more chapters. Return the parent page.
                prev_page = sibling
        return prev_page

    @property
    def zen_nav(self):
        return True

    def breadcrumb_list(self):
        """
        Get all the parent PublicationPages and return a QuerySet
        """
        return Page.objects.ancestor_of(self).type(PublicationPage).live()

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        pages = []
        for page in self.get_children():
            if request.user.is_authenticated:
                # User is logged in, and can preview a page. Get all pages, even drafts.
                pages.append({
                    'child': page,
                    'grandchildren': page.get_children()
                })
            elif page.live:
                # User is not logged in AND this page is live. Only fetch live grandchild pages.
                pages.append({
                    'child': page,
                    'grandchildren': page.get_children().live()
                })
        context['child_pages'] = pages
        return set_main_site_nav_information(self, context, 'Homepage')
    def test(self):
        translatable_fields = get_translatable_fields(
            TestGenerateTranslatableFieldsPage)

        self.assertEqual(translatable_fields, [
            TranslatableField('title'),
            TranslatableField('slug'),
            TranslatableField('seo_title'),
            SynchronizedField('show_in_menus'),
            TranslatableField('search_description'),
            TranslatableField('test_charfield'),
            SynchronizedField('test_charfield_with_choices'),
            TranslatableField('test_textfield'),
            SynchronizedField('test_emailfield'),
            TranslatableField('test_slugfield'),
            SynchronizedField('test_urlfield'),
            TranslatableField('test_richtextfield'),
            TranslatableField('test_streamfield'),
            TranslatableField('test_snippet'),
            SynchronizedField('test_nontranslatablesnippet'),
            TranslatableField('test_customfield'),
            TranslatableField('test_translatable_childobjects'),
            SynchronizedField('test_nontranslatable_childobjects'),
        ])
class YoutubeRegretsPage(FoundationMetadataPageMixin, Page):
    headline = models.CharField(
        max_length=500,
        help_text='Page headline',
        blank=True,
    )

    intro_text = StreamField([
        ('text', blocks.CharBlock()),
    ])

    intro_images = StreamField([
        ('image', customblocks.ImageBlock()),
    ])

    faq = StreamField(
        [('paragraph',
          blocks.RichTextBlock(features=[
              'bold',
              'italic',
              'h2',
              'h3',
              'h4',
              'h5',
              'ol',
              'ul',
              'link',
              'hr',
          ]))],
        blank=True,
    )

    regret_stories = StreamField([
        ('regret_story', customblocks.YoutubeRegretBlock()),
    ])

    content_panels = Page.content_panels + [
        FieldPanel('headline'),
        StreamFieldPanel('intro_text'),
        StreamFieldPanel('intro_images'),
        StreamFieldPanel('faq'),
        StreamFieldPanel('regret_stories'),
    ]

    translatable_fields = [
        # Promote tab fields
        SynchronizedField('slug'),
        TranslatableField('seo_title'),
        SynchronizedField('show_in_menus'),
        TranslatableField('search_description'),
        SynchronizedField('search_image'),
        # Content tab fields
        TranslatableField('title'),
        TranslatableField('headline'),
        TranslatableField('intro_text'),
        TranslatableField('intro_images'),
        TranslatableField('faq'),
        TranslatableField('regret_stories'),
    ]

    zen_nav = True

    def get_context(self, request):
        context = super().get_context(request)
        return set_main_site_nav_information(self, context, 'Homepage')

    template = 'wagtailpages/pages/youtube_regrets_page.html'
Esempio n. 30
0
class Petition(TranslatableMixin, CTA):
    campaign_id = models.CharField(
        max_length=20,
        help_text='Which campaign identifier should this petition be tied to?',
        null=True,
        blank=True,
    )

    requires_country_code = models.BooleanField(
        default=False,
        help_text='Will this petition require users to specify their country?',
    )

    requires_postal_code = models.BooleanField(
        default=False,
        help_text=
        'Will this petition require users to specify their postal code?',
    )

    COMMENT_CHOICES = (
        ('none', 'No comments'),
        ('optional', 'Optional comments'),
        ('required', 'Required comments'),
    )

    comment_requirements = models.CharField(
        choices=COMMENT_CHOICES,
        default='none',
        help_text='What is the comments policy for this petition?',
        max_length=8,
    )

    checkbox_1 = models.CharField(
        editable=False,
        max_length=1024,
        help_text='label for the first checkbox option (may contain HTML)',
        blank=True,
    )

    checkbox_2 = models.CharField(
        editable=False,
        max_length=1024,
        help_text='label for the second checkbox option (may contain HTML)',
        blank=True,
    )

    share_link = models.URLField(
        max_length=1024,
        help_text='Link that will be put in share button',
        blank=True,
        editable=False,
    )

    share_link_text = models.CharField(
        max_length=20,
        help_text='Text content of the share button',
        default='Share this',
        blank=True,
        editable=False,
    )

    share_twitter = models.CharField(
        max_length=20,
        help_text=
        'Share Progress id for twitter button, including the sp_... prefix',
        blank=True,
    )

    share_facebook = models.CharField(
        max_length=20,
        help_text=
        'Share Progress id for facebook button, including the sp_... prefix',
        blank=True,
    )

    share_email = models.CharField(
        max_length=20,
        help_text=
        'Share Progress id for email button, including the sp_... prefix',
        blank=True,
    )

    thank_you = models.CharField(
        max_length=140,
        help_text='Message to show after thanking people for signing',
        default='Thank you for signing too!',
    )

    translatable_fields = [
        # This models fields
        SynchronizedField('requires_country_code'),
        SynchronizedField('requires_postal_code'),
        TranslatableField('comment_requirements'),
        TranslatableField('checkbox_1'),
        TranslatableField('checkbox_2'),
        SynchronizedField('share_twitter'),
        SynchronizedField('share_facebook'),
        SynchronizedField('share_email'),
        TranslatableField('thank_you'),
        # Fields from the CTA model
        TranslatableField('header'),
        TranslatableField('description'),
    ]

    class Meta(TranslatableMixin.Meta):
        verbose_name = 'petition snippet'