Exemple #1
0
 def test_render(self):
     inline_panel = InlinePanel(self.mock_model,
                                'formset',
                                label='foo')(
         instance=self.fake_instance,
         form=self.fake_field)
     self.assertIn('Add foo', inline_panel.render())
Exemple #2
0
 def test_render_js(self):
     inline_panel = InlinePanel(self.mock_model,
                                'formset')(
         instance=self.fake_instance,
         form=self.fake_field)
     self.assertIn('var panel = InlinePanel({',
                   inline_panel.render_js())
    def test_render(self):
        """
        Check that the inline panel renders the panels set on the model
        when no 'panels' parameter is passed in the InlinePanel definition
        """
        SpeakerInlinePanel = InlinePanel('speakers', label="Speakers").bind_to_model(EventPage)
        EventPageForm = SpeakerInlinePanel.get_form_class(EventPage)

        # SpeakerInlinePanel should instruct the form class to include a 'speakers' formset
        self.assertEqual(['speakers'], list(EventPageForm.formsets.keys()))

        event_page = EventPage.objects.get(slug='christmas')

        form = EventPageForm(instance=event_page)
        panel = SpeakerInlinePanel(instance=event_page, form=form)

        result = panel.render_as_field()

        self.assertIn('<label for="id_speakers-0-first_name">Name:</label>', result)
        self.assertIn('value="Father"', result)
        self.assertIn('<label for="id_speakers-0-last_name">Surname:</label>', result)
        self.assertIn('<label for="id_speakers-0-image">Image:</label>', result)
        self.assertIn('Choose an image', result)

        # rendered panel must also contain hidden fields for id, DELETE and ORDER
        self.assertIn('<input id="id_speakers-0-id" name="speakers-0-id" type="hidden"', result)
        self.assertIn('<input id="id_speakers-0-DELETE" name="speakers-0-DELETE" type="hidden"', result)
        self.assertIn('<input id="id_speakers-0-ORDER" name="speakers-0-ORDER" type="hidden"', result)

        # rendered panel must contain maintenance form for the formset
        self.assertIn('<input id="id_speakers-TOTAL_FORMS" name="speakers-TOTAL_FORMS" type="hidden"', result)

        # render_js_init must provide the JS initializer
        self.assertIn('var panel = InlinePanel({', panel.render_js_init())
    def test_old_style_inlinepanel_declaration(self):
        """
        Check that the deprecated form of InlinePanel declaration (where the base model is passed
        as the first arg) still works
        """
        self.reset_warning_registry()
        with warnings.catch_warnings(record=True) as w:
            SpeakerInlinePanelDef = InlinePanel(EventPage, 'speakers', label="Speakers")

            # Check that a RemovedInWagtail12Warning has been triggered
            self.assertEqual(len(w), 1)
            self.assertTrue(issubclass(w[-1].category, RemovedInWagtail12Warning))
            self.assertTrue("InlinePanel(EventPage, 'speakers') should be changed to InlinePanel('speakers')" in str(w[-1].message))

        SpeakerInlinePanel = SpeakerInlinePanelDef.bind_to_model(EventPage)
        EventPageForm = SpeakerInlinePanel.get_form_class(EventPage)

        # SpeakerInlinePanel should instruct the form class to include a 'speakers' formset
        self.assertEqual(['speakers'], list(EventPageForm.formsets.keys()))

        event_page = EventPage.objects.get(slug='christmas')
        form = EventPageForm(instance=event_page)
        panel = SpeakerInlinePanel(instance=event_page, form=form)

        result = panel.render_as_field()
        self.assertIn('<label for="id_speakers-0-first_name">Name:</label>', result)
        self.assertIn('value="Father"', result)
Exemple #5
0
 def test_get_panel_definitions_no_panels(self):
     """
     Check that get_panel_definitions returns the panels set on the model
     when no panels are set on the InlinePanel
     """
     inline_panel = InlinePanel(self.mock_model, 'formset')(
         instance=self.fake_instance,
         form=self.fake_field)
     result = inline_panel.get_panel_definitions()
     self.assertEqual(result[0].name, 'mock panel')
Exemple #6
0
 def test_get_panel_definitions(self):
     """
     Check that get_panel_definitions returns the panels set on
     InlinePanel
     """
     other_mock_panel = MagicMock()
     other_mock_panel.name = 'other mock panel'
     inline_panel = InlinePanel(self.mock_model,
                                'formset',
                                panels=[other_mock_panel])(
         instance=self.fake_instance,
         form=self.fake_field)
     result = inline_panel.get_panel_definitions()
     self.assertEqual(result[0].name, 'other mock panel')
    def test_render_with_panel_overrides(self):
        """
        Check that inline panel renders the panels listed in the InlinePanel definition
        where one is specified
        """
        SpeakerInlinePanel = InlinePanel('speakers', label="Speakers", panels=[
            FieldPanel('first_name', widget=forms.Textarea),
            ImageChooserPanel('image'),
        ]).bind_to_model(EventPage)
        EventPageForm = SpeakerInlinePanel.get_form_class(EventPage)

        # SpeakerInlinePanel should instruct the form class to include a 'speakers' formset
        self.assertEqual(['speakers'], list(EventPageForm.formsets.keys()))

        event_page = EventPage.objects.get(slug='christmas')

        form = EventPageForm(instance=event_page)
        panel = SpeakerInlinePanel(instance=event_page, form=form)

        result = panel.render_as_field()

        # rendered panel should contain first_name rendered as a text area, but no last_name field
        self.assertIn('<label for="id_speakers-0-first_name">Name:</label>', result)
        self.assertIn('Father</textarea>', result)
        self.assertNotIn('<label for="id_speakers-0-last_name">Surname:</label>', result)

        # test for #338: surname field should not be rendered as a 'stray' label-less field
        self.assertNotIn('<input id="id_speakers-0-last_name"', result)

        self.assertIn('<label for="id_speakers-0-image">Image:</label>', result)
        self.assertIn('Choose an image', result)

        # rendered panel must also contain hidden fields for id, DELETE and ORDER
        self.assertIn('<input id="id_speakers-0-id" name="speakers-0-id" type="hidden"', result)
        self.assertIn('<input id="id_speakers-0-DELETE" name="speakers-0-DELETE" type="hidden"', result)
        self.assertIn('<input id="id_speakers-0-ORDER" name="speakers-0-ORDER" type="hidden"', result)

        # rendered panel must contain maintenance form for the formset
        self.assertIn('<input id="id_speakers-TOTAL_FORMS" name="speakers-TOTAL_FORMS" type="hidden"', result)

        # render_js_init must provide the JS initializer
        self.assertIn('var panel = InlinePanel({', panel.render_js_init())
Exemple #8
0
    ]


class EventPage(Page):
    date_from = models.DateField("Start date", null=True)
    date_to = models.DateField(
        "End date",
        null=True,
        blank=True,
        help_text="Not required if event is on a single day")
    time_from = models.TimeField("Start time", null=True, blank=True)
    time_to = models.TimeField("End time", null=True, blank=True)
    location = models.CharField(max_length=255)
    body = RichTextField(blank=True)
    cost = models.CharField(max_length=255)
    signup_link = models.URLField(blank=True)


EventPage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('date_from'),
    FieldPanel('date_to'),
    FieldPanel('time_from'),
    FieldPanel('time_to'),
    FieldPanel('location'),
    FieldPanel('cost'),
    FieldPanel('signup_link'),
    FieldPanel('body', classname="full"),
    InlinePanel('related_media', label="Related media"),
]
Exemple #9
0
class ArticlePage(ThemeablePage, FeatureStyleFields, Promotable, ShareLinksMixin, PageLayoutOptions, VideoDocumentMixin):
    excerpt = RichTextField(blank=True, default="")
    body = article_fields.BodyField()
    chapters = article_fields.ChapterField(blank=True, null=True)
    table_of_contents_heading = models.TextField(blank=True, default="Table of Contents")
    citations_heading = models.TextField(blank=True, default="Works Cited")
    endnotes_heading = models.TextField(blank=True, default="End Notes")
    endnote_identifier_style = models.CharField(
        max_length=20,
        default="roman-lower",
        choices=(
            ('roman-lower', 'Roman Numerals - Lowercase'),
            ('roman-upper', 'Roman Numerals - Uppercase'),
            ('numbers', 'Numbers')
        )
    )

    main_image = models.ForeignKey(
        'images.AttributedImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    feature_image = models.ForeignKey(
        'images.AttributedImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    primary_topic = models.ForeignKey(
        'articles.Topic',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='articles'
    )
    category = models.ForeignKey(
        'articles.ArticleCategory',
        related_name='%(class)s',
        on_delete=models.SET_NULL,
        null=True,
        default=1
    )

    include_author_block = models.BooleanField(default=True)

    visualization = models.BooleanField(default=False)
    interview = models.BooleanField(default=False)
    video = models.BooleanField(default=False)
    number_of_related_articles = models.PositiveSmallIntegerField(default=6,
                                                                  verbose_name="Number of Related Articles to Show")
    json_file = article_fields.WagtailFileField(max_length=255, blank=True, null=True, verbose_name='JSON file',
                                                help_text="Only provide if you know your template will be filled with the contents of a JSON data file.")

    project = models.ForeignKey(
        "projects.ProjectPage",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
    )

    _response_to = False

    search_fields = Page.search_fields + [
        index.SearchField('excerpt', partial_match=True),
        index.SearchField('body', partial_match=True),
        index.SearchField('chapters', partial_match=True),
        index.SearchField('get_primary_topic_name', partial_match=True),
        index.SearchField('get_category_name', partial_match=True),
        index.SearchField('get_topic_names', partial_match=True),
        index.SearchField('get_author_names', partial_match=True),
    ]

    def get_primary_topic_name(self):
        if self.primary_topic:
            return self.primary_topic.name
        return ""

    def get_category_name(self):
        if self.category:
            return self.category.name
        return ""

    def get_topic_names(self):
        return '\n'.join([link.topic.name if link.topic else "" for link in self.topic_links.all()])

    def get_author_names(self):
        return '\n'.join(
            [author_link.author.full_name if author_link.author else "" for author_link in self.author_links.all()])

    @property
    def authors(self):
        author_list = []
        for link in self.author_links.all():
            if link.author:
                author_list.append((link.author))
        return author_list

    @property
    def series_articles(self):
        related_series_data = []
        for link in self.series_links.all():
            series_page = link.series
            series_articles = series_page.articles
            series_articles.remove(self)
            related_series_data.append((series_page, series_articles))
        return related_series_data

    @property
    def topics(self):
        primary_topic = self.primary_topic
        all_topics = [link.topic for link in self.topic_links.all()]
        if primary_topic:
            all_topics.append(primary_topic)
        all_topics = list(set(all_topics))
        if len(all_topics) > 0:
            all_topics.sort(key=attrgetter('name'))
        return all_topics

    @property
    def response_to(self):
        if self._response_to is False:
            response_to_count = self.response_to_links.count()
            if response_to_count > 1:
                logger.warning(
                    'ArticlePage(pk={0}) appears to be a response to multiple articles. Only the first one is being returned.'.format(
                        self.pk
                    )
                )
            if response_to_count != 0:
                self._response_to = self.response_to_links.first().response_to
            else:
                self._response_to = None

        return self._response_to

    @property
    def is_response(self):
        return self.response_to is not None

    def responses(self):
        return [link.response for link in self.response_links.all()]

    def related_articles(self, number):
        included = [self.id]
        article_list = []
        if self.primary_topic:
            articles = ArticlePage.objects.live().filter(primary_topic=self.primary_topic).exclude(
                id=self.id).distinct().order_by('-first_published_at')[:number]
            article_list.extend(articles.all())
            included.extend([article.id for article in articles.all()])

        current_total = len(article_list)

        if current_total < number:
            # still don't have enough, so pick using secondary topics
            topics = Topic.objects.filter(article_links__article=self)
            if topics:
                additional_articles = ArticlePage.objects.live().filter(primary_topic__in=topics).exclude(
                    id__in=included).distinct().order_by('-first_published_at')[:number - current_total]
                article_list.extend(additional_articles.all())
                current_total = len(article_list)
                included.extend([article.id for article in additional_articles.all()])

        if current_total < number:
            authors = ContributorPage.objects.live().filter(article_links__article=self)
            if authors:
                additional_articles = ArticlePage.objects.live().filter(author_links__author__in=authors).exclude(
                    id__in=included).distinct().order_by('-first_published_at')[:number - current_total]
                article_list.extend(additional_articles.all())
                current_total = len(article_list)
                included.extend([article.id for article in additional_articles.all()])

        if current_total < number:
            # still don't have enough, so just pick the most recent
            additional_articles = ArticlePage.objects.live().exclude(id__in=included).order_by('-first_published_at')[:number - current_total]
            article_list.extend(additional_articles.all())

        return article_list

    content_panels = Page.content_panels + [
        FieldPanel('excerpt'),
        InlinePanel('author_links', label="Authors"),
        PageChooserPanel('project'),
        ImageChooserPanel('main_image'),
        ImageChooserPanel('feature_image'),
        DocumentChooserPanel('video_document'),
        StreamFieldPanel('body'),
        SnippetChooserPanel('primary_topic'),
        InlinePanel('topic_links', label="Secondary Topics"),
        InlinePanel('response_links', label="Responses"),
    ]

    advanced_content_panels = [
        FieldPanel('json_file'),
        MultiFieldPanel(
            [
                FieldPanel('table_of_contents_heading'),
                StreamFieldPanel('chapters'),
            ],
            heading="Chapters Section"
        ),
        MultiFieldPanel(
            [
                FieldPanel('endnotes_heading'),
                FieldPanel('endnote_identifier_style'),
                InlinePanel('endnote_links', label="End Notes"),
            ],
            heading="End Notes Section"
        ),
        MultiFieldPanel(
            [
                FieldPanel('citations_heading'),
                InlinePanel('citation_links', label="Citations"),
            ],
            heading="Citations Section"
        ),
    ]

    promote_panels = Page.promote_panels + [
        MultiFieldPanel(
            [
                FieldPanel('sticky'),
                FieldPanel('sticky_for_type_section'),
                FieldPanel('slippery'),
                FieldPanel('slippery_for_type_section'),
                FieldPanel('editors_pick'),
                FieldPanel('feature_style'),
                FieldPanel('title_size'),
                FieldPanel('fullbleed_feature'),
                FieldPanel('image_overlay_opacity'),
            ],
            heading="Featuring Settings"
        ),
    ]

    style_panels = ThemeablePage.style_panels + [

        MultiFieldPanel(
            [
                FieldPanel('include_main_image'),
                FieldPanel('include_main_image_overlay'),
                FieldPanel('full_bleed_image_size'),
                FieldPanel('include_caption_in_footer'),
            ],
            heading="Main Image"
        ),
        MultiFieldPanel(
            [
                InlinePanel('background_image_links', label="Background Images"),
            ],
            heading="Background Images"
        ),
        MultiFieldPanel(
            [
                FieldPanel('include_author_block'),
                FieldPanel('number_of_related_articles')
            ],
            heading="Sections"
        ),
        MultiFieldPanel(
            [
                FieldPanel('interview'),
                FieldPanel('video'),
                FieldPanel('visualization'),
            ],
            heading="Categorization"
        )
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(advanced_content_panels, heading='Advanced Content'),
        ObjectList(style_panels, heading='Page Style Options'),
        ObjectList(promote_panels, heading='Promote'),
        ObjectList(Page.settings_panels, heading='Settings', classname="settings"),
    ])
Exemple #10
0
    )

    password_required_template = 'tests/event_page_password_required.html'


EventPage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('date_from'),
    FieldPanel('date_to'),
    FieldPanel('time_from'),
    FieldPanel('time_to'),
    FieldPanel('location'),
    FieldPanel('audience'),
    FieldPanel('cost'),
    FieldPanel('signup_link'),
    InlinePanel('carousel_items', label="Carousel items"),
    FieldPanel('body', classname="full"),
    InlinePanel('speakers', label="Speakers"),
    InlinePanel('related_links', label="Related links"),
]

EventPage.promote_panels = [
    MultiFieldPanel(COMMON_PANELS, "Common page configuration"),
    ImageChooserPanel('feed_image'),
]


# Just to be able to test multi table inheritance
class SingleEventPage(EventPage):
    excerpt = models.TextField(
        max_length=255,
Exemple #11
0
class SectionedRichTextPage(Page):
    content_panels = [
        FieldPanel('title', classname="full title"),
        InlinePanel('sections')
    ]
Exemple #12
0
class TourPage(Page):

    search_fields = Page.search_fields + [
        index.SearchField('title'),
        index.SearchField('tour_description'),
    ]

    tour_image = models.ForeignKey('wagtailimages.Image',
                                   null=True,
                                   blank=True,
                                   on_delete=models.SET_NULL,
                                   related_name='+',
                                   help_text='Album cover image')

    tour_listing_introduction = models.TextField(
        "A listing introduction for the tour", blank=True, max_length=254)

    tour_description = RichTextField("A description for the tour")

    content_panels = Page.content_panels + [
        InlinePanel('tour_artist_relationship',
                    label="Arist(s)",
                    panels=None,
                    min_num=1),
        InlinePanel('tour_album_relationship',
                    label="Album(s)",
                    panels=None,
                    min_num=0),
        ImageChooserPanel('tour_image'),
        FieldPanel('tour_listing_introduction'),
        FieldPanel('tour_description'),
    ]

    tour_panels = [
        InlinePanel('tourdates',
                    label="Tour dates",
                    help_text="Enter your tour dates",
                    min_num=1),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading="Tour details",
                   classname="content"),
        ObjectList(tour_panels, heading="Tour dates"),
        ObjectList(Page.promote_panels, heading="Promote"),
        ObjectList(Page.settings_panels,
                   heading="Settings",
                   classname="settings"),
    ])

    # We iterate within the model over the artists, genres and subgenres
    # so they can be accessible to the template via a for loop
    def artists(self):
        artists = [n.artists for n in self.tour_artist_relationship.all()]
        return artists

    def albums(self):
        albums = [n.albums for n in self.tour_album_relationship.all()]

        return albums

    @property
    def album_image(self):
        # fail silently if there is no profile pic or the rendition file can't
        # be found. Note @richbrennan worked out how to do this...
        try:
            return self.image.get_rendition('fill-400x400').img_tag()
        except:
            return ''

    parent_page_types = [
        'tours.TourIndexPage'
        # app.model
    ]

    subpage_types = []
Exemple #13
0
class BlogPage(Page):
    """
    A Blog Page

    We access the People object with an inline panel that references the
    ParentalKey's related_name in BlogPeopleRelationship. More docs:
    http://docs.wagtail.io/en/latest/topics/pages.html#inline-models
    """
    introduction = models.TextField(help_text='Text to describe the page',
                                    blank=True)
    image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        help_text=
        'Landscape mode only; horizontal width between 1000px and 3000px.')
    body = StreamField(BaseStreamBlock(), verbose_name="Page body", blank=True)
    subtitle = models.CharField(blank=True, max_length=255)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    date_published = models.DateField("Date article published",
                                      blank=True,
                                      null=True)

    content_panels = Page.content_panels + [
        FieldPanel('subtitle', classname="full"),
        FieldPanel('introduction', classname="full"),
        ImageChooserPanel('image'),
        StreamFieldPanel('body'),
        FieldPanel('date_published'),
        InlinePanel('blog_person_relationship',
                    label="Author(s)",
                    panels=None,
                    min_num=1),
        FieldPanel('tags'),
    ]

    search_fields = Page.search_fields + [
        index.SearchField('body'),
    ]

    def authors(self):
        """
        Returns the BlogPage's related People. Again note that we are using
        the ParentalKey's related_name from the BlogPeopleRelationship model
        to access these objects. This allows us to access the People objects
        with a loop on the template. If we tried to access the blog_person_
        relationship directly we'd print `blog.BlogPeopleRelationship.None`
        """
        authors = [n.people for n in self.blog_person_relationship.all()]

        return authors

    @property
    def get_tags(self):
        """
        Similar to the authors function above we're returning all the tags that
        are related to the blog post into a list we can access on the template.
        We're additionally adding a URL to access BlogPage objects with that tag
        """
        tags = self.tags.all()
        for tag in tags:
            tag.url = '/' + '/'.join(
                s.strip('/')
                for s in [self.get_parent().url, 'tags', tag.slug])
        return tags

    # Specifies parent to BlogPage as being BlogIndexPages
    parent_page_types = ['BlogIndexPage']

    # Specifies what content types can exist as children of BlogPage.
    # Empty list means that no child content types are allowed.
    subpage_types = []
Exemple #14
0
class FormField(AbstractFormField):
    page = ParentalKey('FormPage', related_name='form_fields')


class FormPage(AbstractEmailForm):
    subpage_types = []
    parent_page_types = [HomePage]

    intro = RichTextField(blank=True)
    thank_you_text = RichTextField(blank=True)


FormPage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('intro', classname="full"),
    InlinePanel('form_fields', label="Form fields"),
    FieldPanel('thank_you_text', classname="full"),
    MultiFieldPanel([
        FieldPanel('to_address', classname="full"),
        FieldPanel('from_address', classname="full"),
        FieldPanel('subject', classname="full"),
    ], "Email")
]


@register_setting(icon='icon-group')
class SocialMediaSettings(BaseSetting):
    facebook = models.URLField(blank=True,
                               help_text='Complete URL for facebook page')
    twitter = models.CharField(blank=True,
                               max_length=127,
Exemple #15
0
class AbstractFilterPage(CFGOVPage):
    header = StreamField([
        ('article_subheader', blocks.RichTextBlock(icon='form')),
        ('text_introduction', molecules.TextIntroduction()),
        ('item_introduction', organisms.ItemIntroduction()),
    ],
                         blank=True)
    preview_title = models.CharField(max_length=255, null=True, blank=True)
    preview_subheading = models.CharField(max_length=255,
                                          null=True,
                                          blank=True)
    preview_description = RichTextField(null=True, blank=True)
    secondary_link_url = models.CharField(max_length=500,
                                          null=True,
                                          blank=True)
    secondary_link_text = models.CharField(max_length=255,
                                           null=True,
                                           blank=True)
    preview_image = models.ForeignKey('v1.CFGOVImage',
                                      null=True,
                                      blank=True,
                                      on_delete=models.SET_NULL,
                                      related_name='+')
    date_published = models.DateField(default=date.today)
    date_filed = models.DateField(null=True, blank=True)
    comments_close_by = models.DateField(null=True, blank=True)

    # Configuration tab panels
    settings_panels = [
        MultiFieldPanel(CFGOVPage.promote_panels, 'Settings'),
        InlinePanel('categories', label="Categories", max_num=2),
        FieldPanel('tags', 'Tags'),
        MultiFieldPanel([
            FieldPanel('preview_title', classname="full"),
            FieldPanel('preview_subheading', classname="full"),
            FieldPanel('preview_description', classname="full"),
            FieldPanel('secondary_link_url', classname="full"),
            FieldPanel('secondary_link_text', classname="full"),
            ImageChooserPanel('preview_image'),
        ],
                        heading='Page Preview Fields',
                        classname='collapsible'),
        FieldPanel('authors', 'Authors'),
        MultiFieldPanel([
            FieldPanel('date_published'),
            FieldPanel('date_filed'),
            FieldPanel('comments_close_by'),
        ],
                        'Relevant Dates',
                        classname='collapsible'),
        MultiFieldPanel(Page.settings_panels, 'Scheduled Publishing'),
    ]

    # This page class cannot be created.
    is_creatable = False

    objects = CFGOVPageManager()

    @classmethod
    def generate_edit_handler(self, content_panel):
        content_panels = [
            StreamFieldPanel('header'),
            content_panel,
        ]
        return TabbedInterface([
            ObjectList(self.content_panels + content_panels,
                       heading='General Content'),
            ObjectList(CFGOVPage.sidefoot_panels, heading='Sidebar'),
            ObjectList(self.settings_panels, heading='Configuration'),
        ])

    # Returns an image for the page's meta Open Graph tag
    @property
    def meta_image(self):
        parent_meta = super(AbstractFilterPage, self).meta_image
        return parent_meta or self.preview_image
Exemple #16
0
    class Meta:
        verbose_name = "Homepage"


class HomePageCarouselItem(Orderable, AbstractCarouselItem):
    page = ParentalKey('HomePage', related_name='carousel_items')


class HomePageRelatedLink(Orderable, AbstractRelatedLink):
    page = ParentalKey('HomePage', related_name='related_links')


HomePage.content_panels = Page.content_panels + [
    FieldPanel('body', classname="full"),
    InlinePanel(HomePage, 'carousel_items', label="Carousel items"),
    InlinePanel(HomePage, 'related_links', label="Related links"),
]

# Standard pages


class StandardPage(Page):
    intro = RichTextField(blank=True)
    body = RichTextField(blank=True)
    feed_image = models.ForeignKey('wagtailimages.Image',
                                   null=True,
                                   blank=True,
                                   on_delete=models.SET_NULL,
                                   related_name='+')
Exemple #17
0
class CountryPage(Page, HeroImageFields, SocialFields, ListingFields):
    body = StreamField(StoryBlock())
    partners_title = models.CharField(
        blank=True,
        null=True,
        max_length=255,
        help_text='Title text to appear as Partnerships heading.')
    partners_description = RichTextField(
        blank=True,
        null=True,
        help_text=
        'Description text to appear below Partnerships heading for Partnership block.',
        features=['bold', 'italic', 'link', 'justify'])
    person_category = models.ForeignKey(
        'people.PersonCategory',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        help_text="Select a person category to display its team members.",
        related_name='+',
    )
    call_to_action = models.ForeignKey('utils.CallToActionSnippet',
                                       null=True,
                                       blank=True,
                                       on_delete=models.SET_NULL,
                                       related_name='+')
    featured_article = models.ForeignKey(
        'articles.ArticlePage',
        verbose_name="Featured News",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        help_text=
        "Select a featured article to display first in article section",
        related_name='+',
    )

    @cached_property
    def articles(self):
        # returns articles that have solution selected as a related page
        all_articles = ArticlePage.objects.filter(
            related_pages__page=self).live().public().order_by(
                '-publication_date')
        if self.featured_article_id:
            all_articles = all_articles.exclude(pk=self.featured_article_id)
        return all_articles[:3]

    @cached_property
    def people(self):
        if self.person_category:
            return self.person_category.people
        else:
            return None

    @cached_property
    def partners(self):
        partners = [p.related_partner for p in self.related_partners.all()]
        return partners

    @cached_property
    def article_customisations(self):
        return self.articles_customisation.first()

    @cached_property
    def partners_customisations(self):
        return self.partners_customisation.first()

    search_fields = Page.search_fields + HeroImageFields.search_fields + [
        index.SearchField('body')
    ]

    content_panels = Page.content_panels + HeroImageFields.content_panels + [
        StreamFieldPanel('body'),
        MultiFieldPanel([
            InlinePanel('articles_customisation',
                        label="Articles Listing Customisation",
                        max_num=1),
            PageChooserPanel('featured_article'),
        ], 'Articles Listing'),
        MultiFieldPanel([
            FieldPanel('partners_title'),
            FieldPanel('partners_description'),
            InlinePanel('related_partners', label="Related partners"),
            InlinePanel('partners_customisation',
                        label="Partners Customisation",
                        max_num=1),
        ], 'Partners Listing'),
        SnippetChooserPanel('call_to_action'),
    ]

    promote_panels = Page.promote_panels + SocialFields.promote_panels \
        + ListingFields.promote_panels
class InlinePanelPage(WagtailPage):
    content_panels = [
        InlinePanel('related_page_model')
    ]
class InlinePanelSnippet(models.Model):
    panels = [
        InlinePanel('related_snippet_model')
    ]
Exemple #20
0
class HomePage(Page, LocalorePromoteFields):
    site_intro = RichTextField(blank=True)

    related_content_title = models.CharField(
        verbose_name="title",
        max_length=255,
    )
    related_content_page = models.ForeignKey('wagtailcore.Page',
                                             verbose_name="page to link to",
                                             null=True,
                                             blank=True,
                                             on_delete=models.SET_NULL,
                                             related_name='+')
    related_content_subtitle = models.CharField(verbose_name="subtitle",
                                                max_length=255,
                                                blank=True,
                                                default="Across America")

    video_poster_image = models.ForeignKey('localore_admin.LocaloreImage',
                                           verbose_name="poster image",
                                           null=True,
                                           on_delete=models.SET_NULL,
                                           related_name='+')
    video_poster_image_mobile = models.ForeignKey(
        'localore_admin.LocaloreImage',
        verbose_name="poster image (mobile)",
        null=True,
        on_delete=models.SET_NULL,
        related_name='+')
    video_mp4 = models.ForeignKey('wagtaildocs.Document',
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL,
                                  related_name='+')
    video_webm = models.ForeignKey('wagtaildocs.Document',
                                   null=True,
                                   blank=True,
                                   on_delete=models.SET_NULL,
                                   related_name='+')
    video_ogv = models.ForeignKey('wagtaildocs.Document',
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL,
                                  related_name='+')

    video_youtube_id = models.CharField(
        verbose_name="YouTube video ID",
        max_length=12,
        default="j6IIjLK-8fU",
        help_text=format_html(
            "The part in bold: "
            "https://www.youtube.com/watch?v=<b>j6IIjLK-8fU</b>"),
    )
    video_is_360 = models.BooleanField(
        "360˚ video",
        default=False,
        help_text="This is a 360-degree video.",
    )

    view_more_title = models.CharField(
        verbose_name='"View more" link title',
        max_length=255,
        help_text='For example, "View more connections"',
    )
    view_more_page = models.ForeignKey('wagtailcore.Page',
                                       verbose_name="Page to link to",
                                       null=True,
                                       on_delete=models.SET_NULL,
                                       related_name='+')

    content_panels = Page.content_panels + [
        FieldPanel('site_intro', classname="full"),
        MultiFieldPanel([
            FieldPanel('related_content_title'),
            FieldPanel('related_content_subtitle'),
            PageChooserPanel('related_content_page'),
        ], "Featured content"),
        MultiFieldPanel([
            ImageChooserPanel('video_poster_image'),
            ImageChooserPanel('video_poster_image_mobile'),
            DocumentChooserPanel('video_mp4'),
            DocumentChooserPanel('video_webm'),
            DocumentChooserPanel('video_ogv'),
        ], "Hero section"),
        MultiFieldPanel([
            FieldPanel('video_youtube_id'),
            FieldPanel('video_is_360'),
            FieldPanel('view_more_title'),
            PageChooserPanel('view_more_page'),
        ], "Fullscreen video"),
        InlinePanel(
            'featured_pages',
            label="Featured Pages",
            min_num=3,
            max_num=3,
        ),
    ]

    promote_panels = LocalorePromoteFields.promote_panels

    parent_page_types = []

    @property
    def video_poster_image_file_extension(self):
        return self.video_poster_image.file.url.split('.')[-1]

    @property
    def preview_modes(self):
        return super(HomePage, self).preview_modes + [
            ('no-video', 'Preview poster image'),
        ]

    def serve_preview(self, request, mode_name):
        if mode_name == 'no-video':
            self.video_mp4 = None

        return super(HomePage, self).serve_preview(request, mode_name)

    class Meta:
        verbose_name = "Homepage"
Exemple #21
0
class NavigationMenuManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(menu_name=name)


@register_snippet
@python_2_unicode_compatible
class NavigationMenu(ClusterableModel):

    objects = NavigationMenuManager()
    menu_name = models.CharField(max_length=255, null=False, blank=False)

    @property
    def items(self):
        return self.menu_items.all()

    def __str__(self):
        return self.menu_name

    class Meta:
        verbose_name = "Navigation menu"


NavigationMenu.panels = [
    FieldPanel('menu_name', classname='full title'),
    InlinePanel('menu_items',
                label="Menu Items",
                help_text='Set the menu items for the current menu.')
]
Exemple #22
0
    def test_render_with_panel_overrides(self):
        """
        Check that inline panel renders the panels listed in the InlinePanel definition
        where one is specified
        """
        SpeakerObjectList = ObjectList([
            InlinePanel('speakers',
                        label="Speakers",
                        panels=[
                            FieldPanel('first_name', widget=forms.Textarea),
                            ImageChooserPanel('image'),
                        ]),
        ]).bind_to_model(EventPage)
        SpeakerInlinePanel = SpeakerObjectList.children[0]
        EventPageForm = SpeakerObjectList.get_form_class(EventPage)

        # SpeakerInlinePanel should instruct the form class to include a 'speakers' formset
        self.assertEqual(['speakers'], list(EventPageForm.formsets.keys()))

        event_page = EventPage.objects.get(slug='christmas')

        form = EventPageForm(instance=event_page)
        panel = SpeakerInlinePanel(instance=event_page, form=form)

        result = panel.render_as_field()

        # rendered panel should contain first_name rendered as a text area, but no last_name field
        self.assertIn('<label for="id_speakers-0-first_name">Name:</label>',
                      result)
        self.assertIn('Father</textarea>', result)
        self.assertNotIn(
            '<label for="id_speakers-0-last_name">Surname:</label>', result)

        # test for #338: surname field should not be rendered as a 'stray' label-less field
        self.assertTagInHTML('<input id="id_speakers-0-last_name">',
                             result,
                             count=0,
                             allow_extra_attrs=True)

        self.assertIn('<label for="id_speakers-0-image">Image:</label>',
                      result)
        self.assertIn('Choose an image', result)

        # rendered panel must also contain hidden fields for id, DELETE and ORDER
        self.assertTagInHTML(
            '<input id="id_speakers-0-id" name="speakers-0-id" type="hidden">',
            result,
            allow_extra_attrs=True)
        self.assertTagInHTML(
            '<input id="id_speakers-0-DELETE" name="speakers-0-DELETE" type="hidden">',
            result,
            allow_extra_attrs=True)
        self.assertTagInHTML(
            '<input id="id_speakers-0-ORDER" name="speakers-0-ORDER" type="hidden">',
            result,
            allow_extra_attrs=True)

        # rendered panel must contain maintenance form for the formset
        self.assertTagInHTML(
            '<input id="id_speakers-TOTAL_FORMS" name="speakers-TOTAL_FORMS" type="hidden">',
            result,
            allow_extra_attrs=True)

        # render_js_init must provide the JS initializer
        self.assertIn('var panel = InlinePanel({', panel.render_js_init())
Exemple #23
0
class ArticlePage(Page):
    parent_page_types = ["ArticleIndexPage"]
    subpage_types = []

    author = models.ForeignKey(
        'AuthorPage',
        null=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    main_image = models.ForeignKey(
        'images.CustomImage',
        null=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    date = models.DateField("Post date")
    intro = models.TextField(
        max_length=250,
        help_text='This will only appear in article previews, not with the full article. This text will be formatted with markdown.')
    body = StreamField([
        ('text', blocks.TextBlock(icon='pilcrow', help_text='This text will be formatted with markdown.')),
        ('image', CaptionedImageBlock()),
        ('embed', EmbedBlock(icon='media')),
        ('extra_information', ExtraInformationBlock()),
    ])

    search_fields = Page.search_fields + (
        index.SearchField('intro'),
        index.SearchField('body'),
        index.SearchField('author')
    )

    content_panels = Page.content_panels + [
        PageChooserPanel('author'),
        InlinePanel('subjects', label='Subjects'),
        FieldPanel('date'),
        InlinePanel('source_links', label="Sources"),
        ImageChooserPanel('main_image'),
        FieldPanel('intro'),
        StreamFieldPanel('body'),
    ]

    class Meta:
        verbose_name = "Article"

    def __unicode__(self):
        return self.title

    def article_index(self):
        # Find closest ancestor which is article page
        return self.get_ancestors().type(ArticleIndexPage).last()

    """def subject(self):
        # TODO: Replace/remove
        subject = ArticleIndexPage.objects.ancestor_of(self).last().subject
        if subject is not None:
            return subject
        else:
            return ""
    """

    def all_subjects(self):
        # TODO: Replace/remove
        subjects = []
        for s in SubjectSnippet.objects.all():
            subjects.append(ArticleIndexPage.objects.filter(subject=s)[0])
        return subjects
Exemple #24
0
 def test_invalid_inlinepanel_declaration(self):
     with self.ignore_deprecation_warnings():
         self.assertRaises(TypeError, lambda: InlinePanel(label="Speakers"))
         self.assertRaises(
             TypeError, lambda: InlinePanel(
                 EventPage, 'speakers', label="Speakers", bacon="chunky"))
Exemple #25
0
    value = models.CharField(max_length=255)
    project = ParentalKey('portfolio.Project',related_name='metafields')

    def __unicode__(self):
        return self.project.__unicode__() + u'\'s ' + self.key.__unicode__() + u': ' + self.value

class Project(Page):
    description = RichTextField(blank=True)

    indexed_fields = ('description', ) 
    # possibly "metafields.list('values')" (a callable to return list of values)
    # or create some other Project function -- look at how wagtail does tag indexing

Project.content_panels = Page.content_panels + [
    FieldPanel('description', classname="full"),
    InlinePanel(Project, 'metafields', label="MetaFields"),
    InlinePanel(Project, 'images', label="Images"),
]

class ProjectCategory(Page):
    class Meta:
        verbose_name_plural = 'Portfolio Categories'

    subpage_types = ['portfolio.Project']

ProjectCategory.content_panels = Page.content_panels + [
    InlinePanel(ProjectCategory, 'default_metafields', label="Default MetaFields"),
]

class ProjectCategoryIndex(Page):
    subpage_types = ['portfolio.ProjectCategory']
Exemple #26
0
class HomePage(Page):
    title_text = RichTextField(null=True, blank=True)
    body = RichTextField(null=True, blank=True)

    search_fields = Page.search_fields + (
        index.SearchField('body'),
    )

    class Meta:
        verbose_name = "Homepage"

HomePage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('title_text', classname="full"),
    FieldPanel('body', classname="full"),
    InlinePanel('carousel_items', label="Carousel items"),
    InlinePanel('content_items', label="Content Blocks"),
    InlinePanel('related_links', label="Related links"),
]

HomePage.promote_panels = Page.promote_panels


class StandardIndexPageRelatedLink(Orderable, RelatedLink):
    page = ParentalKey('pages.StandardIndexPage', related_name='related_links')


class StandardIndexPage(Page):
    subtitle = models.CharField(max_length=255, blank=True)
    intro = RichTextField(blank=True)
    feed_image = models.ForeignKey(
Exemple #27
0
class FlatMenu(Menu):
    site = models.ForeignKey(
        'wagtailcore.Site',
        verbose_name=_('site'),
        related_name="flat_menus",
        db_index=True, on_delete=models.CASCADE
    )
    title = models.CharField(
        max_length=255,
        help_text=_("For internal reference only."))
    handle = models.SlugField(
        max_length=100,
        help_text=_(
            "Used to reference this menu in templates etc. Must be unique "
            "for the selected site."
        )
    )
    heading = models.CharField(
        max_length=255,
        blank=True,
        help_text=_("If supplied, appears above the menu when rendered.")
    )
    max_levels = models.PositiveSmallIntegerField(
        verbose_name=_('maximum levels'),
        choices=app_settings.MAX_LEVELS_CHOICES,
        default=1,
        help_text=mark_safe(_(
            "The maximum number of levels to display when rendering this "
            "menu. The value can be overidden by supplying a different "
            "<code>max_levels</code> value to the <code>{% flat_menu %}"
            "</code> tag in your templates."
        ))
    )
    use_specific = models.PositiveSmallIntegerField(
        verbose_name=_('specific page usage'),
        choices=app_settings.USE_SPECIFIC_CHOICES,
        default=app_settings.USE_SPECIFIC_AUTO,
        help_text=mark_safe(_(
            "Controls how 'specific' pages objects are fetched and used when "
            "rendering this menu. This value can be overidden by supplying a "
            "different <code>use_specific</code> value to the <code>"
            "{% flat_menu %}</code> tag in your templates."
        ))
    )

    base_form_class = FlatMenuAdminForm

    class Meta:
        unique_together = ("site", "handle")
        verbose_name = _("flat menu")
        verbose_name_plural = _("flat menus")

    @classmethod
    def get_for_site(cls, handle, site,
                     fall_back_to_default_site_menus=False):
        """
        Get a FlatMenu instance with a matching `handle` for the `site`
        provided - or for the 'default' site if not found.
        """
        menu = cls.objects.filter(handle__exact=handle, site=site).first()
        if(
            menu is None and fall_back_to_default_site_menus and
            not site.is_default_site
        ):
            return cls.objects.filter(
                handle__exact=handle, site__is_default_site=True
            ).first()
        return menu

    def __str__(self):
        return '%s (%s)' % (self.title, self.handle)

    def clean(self, *args, **kwargs):
        # Raise validation error for unique_together constraint, as it's not
        # currently handled properly by wagtail
        clashes = FlatMenu.objects.filter(site=self.site, handle=self.handle)
        if self.pk:
            clashes = clashes.exclude(pk__exact=self.pk)
        if clashes.count():
            msg = _("Site and handle must create a unique combination. A menu "
                    "already exists with these same two values.")
            raise ValidationError({
                'site': [msg],
                'handle': [msg],
            })
        super(FlatMenu, self).clean(*args, **kwargs)

    panels = (
        MultiFieldPanel(
            heading=_("Settings"),
            children=(
                FieldPanel('title'),
                FieldPanel('site'),
                FieldPanel('handle'),
                FieldPanel('heading'),
            )
        ),
        InlinePanel('menu_items', label=_("menu items")),
        MultiFieldPanel(
            heading=_("Advanced settings"),
            children=(FieldPanel('max_levels'), FieldPanel('use_specific')),
            classname="collapsible collapsed",
        ),
    )
Exemple #28
0
    search_name = 'Index Page'
    subpage_types = ['IndexPage', 'RichTextPage', 'BlogIndexPage']


class IndexPageRelatedLink(Orderable, AbstractRelatedLink):
    page = ParentalKey('wagtailbase.IndexPage', related_name='related_links')


class IndexPageAttachment(Orderable, AbstractAttachment):
    page = ParentalKey('wagtailbase.IndexPage', related_name='attachments')


IndexPage.content_panels = [
    FieldPanel('title', classname='full title'),
    FieldPanel('introduction', classname='full'),
    InlinePanel(IndexPage, 'related_links', label='Related links'),
    InlinePanel(IndexPage, 'attachments', label='Attachments')
]

IndexPage.promote_panels = [
    MultiFieldPanel(BaseIndexPage.promote_panels, "Common page configuration"),
]


class RichTextPage(BaseRichTextPage):
    search_name = 'Rich Text Page'
    subpage_types = []


class RichTextPageRelatedLink(Orderable, AbstractRelatedLink):
    page = ParentalKey('wagtailbase.RichTextPage',
Exemple #29
0
class InlineStreamPage(Page):
    content_panels = [
        FieldPanel('title', classname="full title"),
        InlinePanel('sections')
    ]
    youtube_blurb = RichTextField(blank=True, default='')
    get_started_now_page = models.ForeignKey(Page,
                                             blank=True,
                                             null=True,
                                             on_delete=models.SET_NULL,
                                             related_name='homepages')


HomePage.content_panels = [
    MultiFieldPanel(
        [FieldPanel('title')],
        heading='Title',
        classname='collapsible collapsed',
    ),
    MultiFieldPanel(
        [InlinePanel('hero_items')],
        heading='Hero images',
        classname='collapsible collapsed',
    ),
    MultiFieldPanel(
        [InlinePanel('highlights')],
        heading='Highlights',
        classname='collapsible collapsed',
    ),
    MultiFieldPanel(
        [
            FieldPanel('youtube_video_id'),
            FieldPanel('youtube_video_title'),
            FieldPanel('youtube_blurb'),
        ],
        heading='Youtube video information',
Exemple #31
0
        index.SearchField('body'),
    )

    password_required_template = 'tests/event_page_password_required.html'

EventPage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('date_from'),
    FieldPanel('date_to'),
    FieldPanel('time_from'),
    FieldPanel('time_to'),
    FieldPanel('location'),
    FieldPanel('audience'),
    FieldPanel('cost'),
    FieldPanel('signup_link'),
    InlinePanel(EventPage, 'carousel_items', label="Carousel items"),
    FieldPanel('body', classname="full"),
    InlinePanel(EventPage, 'speakers', label="Speakers"),
    InlinePanel(EventPage, 'related_links', label="Related links"),
]

EventPage.promote_panels = [
    MultiFieldPanel(COMMON_PANELS, "Common page configuration"),
    ImageChooserPanel('feed_image'),
]


# Event index (has a separate AJAX template, and a custom template context)
class EventIndex(Page):
    intro = RichTextField(blank=True)
    ajax_template = 'tests/includes/event_listing.html'
Exemple #32
0
class ForwardLookingActivity(Study):
    parent_page_types = ['pages.StaticIndex']

    phase_of_policy = models.ForeignKey(
        'PhasesOfPolicy',
        verbose_name='phases of policy cycle',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
    )

    environmental_themes = ParentalManyToManyField(
        'flis_metadata.EnvironmentalTheme',
        verbose_name='topics',
        blank=True)

    additional_information_phase = models.TextField(
        ('additional information about the application'),
        blank=True)

    foresight_approaches = ParentalManyToManyField(
        'ForesightApproach',
        verbose_name='foresight approaches used')

    stakeholder_participation = models.BooleanField(
        'stakeholder participation',
        default=False)

    additional_information_stakeholder = models.TextField(
        'additional information about stakeholder involvement',
        blank=True)

    content_panels = Study.content_panels + [
        FieldPanel('requested_by'),
        MultiFieldPanel([FieldRowPanel([
            FieldPanel('start_date'),
            FieldPanel('end_date')
        ])]
            , 'Timing'
        ),
        MultiFieldPanel([
            FieldPanel('environmental_themes'),
            FieldPanel('geographical_scope'),
            FieldPanel('countries', widget=SelectMultiple),
        ], 'Scope of study'),
        MultiFieldPanel([
            FieldPanel('lead_author'),
            FieldPanel('other'),
        ], 'References and contact information'),
        MultiFieldPanel([
            FieldPanel('purpose_and_target'),
            FieldPanel('additional_information'),
        ], 'Purpose and target audience'),

        MultiFieldPanel([
            FieldPanel('phase_of_policy'),
            FieldPanel('additional_information_phase'),
        ], 'Application of forward looking information in policy cycle'),

        MultiFieldPanel([
            FieldPanel('foresight_approaches'),
            FieldPanel('stakeholder_participation'),
            FieldPanel('additional_information_stakeholder'),
        ], 'Methods and methodology used'),
        InlinePanel('outcomes', label='Outcomes'),
    ]

    class Meta:
        verbose_name_plural = 'Forward looking activities'
Exemple #33
0
class SeriesPage(ThemeablePage, FeatureStyleFields, Promotable, ShareLinksMixin, PageLayoutOptions, VideoDocumentMixin):
    subtitle = RichTextField(blank=True, default="")
    short_description = RichTextField(blank=True, default="")
    body = article_fields.BodyField(blank=True, default="")

    main_image = models.ForeignKey(
        'images.AttributedImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    feature_image = models.ForeignKey(
        'images.AttributedImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    primary_topic = models.ForeignKey(
        'articles.Topic',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='series'
    )
    project = models.ForeignKey(
        "projects.ProjectPage",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
    )

    search_fields = Page.search_fields + [
        index.SearchField('subtitle', partial_match=True),
        index.SearchField('body', partial_match=True),
        index.SearchField('get_primary_topic_name', partial_match=True),
        index.SearchField('get_topic_names', partial_match=True),
    ]

    number_of_related_articles = models.PositiveSmallIntegerField(default=6,
                                                                  verbose_name="Number of Related Articles to Show")

    def get_primary_topic_name(self):
        if self.primary_topic:
            return self.primary_topic.name
        else:
            ""

    def get_topic_names(self):
        return '\n'.join([topic.name if topic else "" for topic in self.topics])

    def get_author_names(self):
        return '\n'.join([author.full_name if author else "" for author in self.authors])

    @property
    def articles(self):
        article_list = []
        for article_link in self.related_article_links.all():
            if article_link.article:
                article_link.article.override_text = article_link.override_text
                article_link.article.override_image = article_link.override_image
                article_list.append(article_link.article)
        return article_list

    @property
    def authors(self):
        author_list = []
        for article_link in self.related_article_links.all():
            if article_link.article:
                if article_link.article:
                    for author_link in article_link.article.author_links.all():
                        if author_link.author:
                            if author_link.author not in author_list:
                                author_list.append(author_link.author)
        author_list.sort(key=attrgetter('last_name'))
        return author_list

    @property
    def topics(self):
        all_topics = []
        if self.primary_topic:
            all_topics.append(self.primary_topic)
        for article_link in self.related_article_links.all():
            if article_link.article:
                all_topics.extend(article_link.article.topics)

        all_topics = list(set(all_topics))
        if all_topics:
            all_topics.sort(key=attrgetter('name'))
        return all_topics

    @property
    def related_series(self):
        related_series_list = []
        if self.project:
            related_series_list = self.project.get_related_series(self)
        return related_series_list

    def related_articles(self, number):
        articles = []
        if self.primary_topic:
            articles = list(ArticlePage.objects.live().filter(primary_topic=self.primary_topic).distinct().order_by(
                '-first_published_at')[:number])

        current_total = len(articles)
        if current_total < number:
            for article in self.articles:
                articles.extend(list(article.related_articles(number)))
                articles = list(set(articles))[:number]
                current_total = len(articles)

                if current_total >= number:
                    return articles

        return articles

    content_panels = Page.content_panels + [
        FieldPanel('subtitle'),
        FieldPanel('short_description'),
        PageChooserPanel('project'),
        ImageChooserPanel('main_image'),
        ImageChooserPanel('feature_image'),
        DocumentChooserPanel('video_document'),
        StreamFieldPanel('body'),
        InlinePanel('related_article_links', label="Articles"),
        SnippetChooserPanel('primary_topic'),
    ]

    promote_panels = Page.promote_panels + [
        MultiFieldPanel(
            [
                FieldPanel('sticky'),
                FieldPanel('sticky_for_type_section'),
                FieldPanel('slippery'),
                FieldPanel('slippery_for_type_section'),
                FieldPanel('editors_pick'),
                FieldPanel('feature_style'),
                FieldPanel('title_size'),
                FieldPanel('fullbleed_feature'),
                FieldPanel('image_overlay_opacity'),
            ],
            heading="Featuring Settings"
        )
    ]

    style_panels = ThemeablePage.style_panels + [
        MultiFieldPanel(
            [
                FieldPanel('include_main_image'),
                FieldPanel('include_main_image_overlay'),
                FieldPanel('full_bleed_image_size'),
                FieldPanel('include_caption_in_footer'),
            ],
            heading="Main Image"
        ),
        MultiFieldPanel(
            [
                FieldPanel('number_of_related_articles'),
            ],
            heading="Sections"
        )
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(style_panels, heading='Page Style Options'),
        ObjectList(promote_panels, heading='Promote'),
        ObjectList(Page.settings_panels, heading='Settings', classname="settings"),
    ])
Exemple #34
0
    feed_image = models.ForeignKey('wagtailimages.Image',
                                   null=True,
                                   blank=True,
                                   on_delete=models.SET_NULL,
                                   related_name='+')

    indexed_fields = ('get_audience_display', 'location', 'body')
    search_name = "Event"


EventPage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('date_from'),
    FieldPanel('date_to'),
    FieldPanel('time_from'),
    FieldPanel('time_to'),
    FieldPanel('location'),
    FieldPanel('audience'),
    FieldPanel('cost'),
    FieldPanel('signup_link'),
    InlinePanel(EventPage, 'carousel_items', label="Carousel items"),
    FieldPanel('body', classname="full"),
    InlinePanel(EventPage, 'speakers', label="Speakers"),
    InlinePanel(EventPage, 'related_links', label="Related links"),
]

EventPage.promote_panels = [
    MultiFieldPanel(COMMON_PANELS, "Common page configuration"),
    ImageChooserPanel('feed_image'),
]
Exemple #35
0
 def test_required_formsets(self):
     inline_panel = InlinePanel(self.mock_model, 'formset')(
         instance=self.fake_instance,
         form=self.fake_field)
     self.assertEqual(inline_panel.required_formsets(), ['formset'])
class Office(JobLocation):
    panels = [
        FieldPanel('abbreviation'),
        FieldPanel('name'),
        InlinePanel('cities', label="Office location", max_num=1),
    ]
Exemple #37
0
        [
            FieldPanel('commenting_state'),
            FieldPanel('commenting_open_time'),
            FieldPanel('commenting_close_time'),
        ],
        heading="Commenting Settings",
    ),
    MultiFieldPanel(
        [
            FieldPanel('social_media_title'),
            FieldPanel('social_media_description'),
            ImageChooserPanel('social_media_image'),
        ],
        heading="Social Media",
    ),
    InlinePanel('related_sections', label="Related Sections"),
]

ArticlePage.promote_panels = [
    MultiFieldPanel(ArticlePage.featured_promote_panels, "Featuring"),
    MultiFieldPanel(ArticlePage.metedata_promote_panels, "Metadata"),
    MultiFieldPanel(Page.promote_panels, "Common page configuration",
                    "collapsible collapsed")
]


class ArticlePageRelatedSections(Orderable):
    page = ParentalKey(ArticlePage, related_name='related_sections')
    section = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
Exemple #38
0
        return self.url

    def get_blog_index(self):
        # Find closest ancestor which is a blog index
        return self.get_ancestors().type(BlogIndexPage).last()

    def get_context(self, request, *args, **kwargs):
        context = super(BlogPage, self).get_context(request, *args, **kwargs)
        context['blogs'] = self.get_blog_index().blogindexpage.blogs
        context = get_blog_context(context)
        context['COMMENTS_APP'] = COMMENTS_APP
        return context

    class Meta:
        verbose_name = _('Blog page')
        verbose_name_plural = _('Blog pages')

    parent_page_types = ['blog.BlogIndexPage']


BlogPage.content_panels = [
    FieldPanel('title', classname="full title"),
    MultiFieldPanel([
        FieldPanel('tags'),
        InlinePanel('categories', label=_("Categories")),
    ], heading="Tags and Categories"),
    ImageChooserPanel('header_image'),
    FieldPanel('body', classname="full"),
    FieldPanel('show_comments')
]