class WhyInvestInTheUKPagePanels:

    content_panels = [
        MultiFieldPanel(
            heading="Hero and Intro",
            classname='collapsible',
            children=[
                FieldPanel('title'),
                ImageChooserPanel('hero_image'),
                MediaChooserPanel('hero_video'),
                FieldPanel('strapline'),
                FieldPanel('introduction'),
                ImageChooserPanel('intro_image'),
            ],
        ),
        MultiFieldPanel(
            heading="UK Strengths",
            classname='collapsible',
            children=[
                FieldPanel('uk_strength_title'),
                FieldPanel('uk_strength_intro'),
                StreamFieldPanel('uk_strength_panels'),
            ],
        ),
        SearchEngineOptimisationPanel()
    ]
    settings_panels = [
        FieldPanel('slug'),
    ]

    edit_handler = make_translated_interface(content_panels=content_panels,
                                             settings_panels=settings_panels)
class AboutUkRegionListingPagePanels:
    image_panels = [
        ImageChooserPanel('hero_image'),
        MediaChooserPanel('hero_video')
    ]

    content_panels = [
        FieldPanel('title'),
        FieldPanel('breadcrumbs_label'),
        MultiFieldPanel(
            heading="Hero",
            children=[
                FieldPanel('hero_title'),
            ],
        ),
        FieldPanel('intro'),
        MultiFieldPanel(heading="Contact us section",
                        classname="collapsible",
                        children=[
                            FieldPanel('contact_title'),
                            FieldPanel('contact_text'),
                            FieldPanel('contact_cta_text'),
                            FieldPanel('contact_cta_link'),
                        ]),
        MultiFieldPanel(
            heading="Explore more of the Investment Atlas section",
            classname="collapsible",
            children=[
                PageChooserPanel('related_page_one', [
                    'great_international.WhyInvestInTheUKPage',
                    'great_international.InternationalTopicLandingPage',
                    'great_international.AboutUkRegionPage',
                    'great_international.InvestmentOpportunityPage'
                ]),
                PageChooserPanel('related_page_two', [
                    'great_international.WhyInvestInTheUKPage',
                    'great_international.InternationalTopicLandingPage',
                    'great_international.AboutUkRegionPage',
                    'great_international.InvestmentOpportunityPage'
                ]),
                PageChooserPanel('related_page_three', [
                    'great_international.WhyInvestInTheUKPage',
                    'great_international.InternationalTopicLandingPage',
                    'great_international.AboutUkRegionPage',
                    'great_international.InvestmentOpportunityPage'
                ]),
            ]),
        SearchEngineOptimisationPanel()
    ]

    settings_panels = [
        FieldPanel('slug'),
    ]

    edit_handler = make_translated_interface(content_panels=content_panels,
                                             settings_panels=settings_panels,
                                             other_panels=[
                                                 ObjectList(image_panels,
                                                            heading='Images'),
                                             ])
示例#3
0
class FeatureAspect(ClusterableModel):
    title = models.CharField(max_length=255)
    video_url = models.URLField(blank=True)
    screenshot = models.ForeignKey(
        "images.WagtailIOImage",
        models.SET_NULL,
        null=True,
        blank=True,
        related_name="+",
    )
    video = models.ForeignKey('wagtailmedia.Media',
                              null=True,
                              blank=True,
                              on_delete=models.SET_NULL,
                              related_name='+')

    def __str__(self):
        return self.title

    panels = [
        FieldPanel("title"),
        InlinePanel("bullets", label="Bullets"),
        ImageChooserPanel("screenshot"),
        FieldPanel("video_url"),
        MediaChooserPanel('video'),
    ]
示例#4
0
class HeroVideoFieldsLogo(HeroVideoFields):
    hero_logo = models.ForeignKey(
        'images.CustomImage',
        null=True,
        blank=True,
        related_name='+',
        help_text="Shows the brand logo on the hero instead of a text heading.",
        on_delete=models.SET_NULL,
        verbose_name="Brand Logo")

    content_panels = [
        MultiFieldPanel([
            MediaChooserPanel('hero_video'),
            ImageChooserPanel('hero_fallback_image'),
            ImageChooserPanel('hero_logo'),
            FieldPanel('hero_strapline'),
            FieldPanel('hero_strapline_hex'),
            MultiFieldPanel([
                PageChooserPanel('link_page'),
                FieldPanel('link_youtube'),
                FieldPanel('link_text'),
            ], 'Hero Clickthrough Link')
        ], 'Hero Video'),
    ]

    class Meta:
        abstract = True
 def _init_edit_handler(self, media_type=None):
     my_page_object_list = ObjectList(
         [MediaChooserPanel("featured_media", media_type=media_type)]
     ).bind_to(model=BlogStreamPage)
     my_media_chooser_panel = my_page_object_list.children[0]
     form = my_page_object_list.get_form_class()(instance=self.test_instance)
     media_chooser_panel = my_media_chooser_panel.bind_to(
         instance=self.test_instance, form=form, request=self.request
     )
     return form, media_chooser_panel
示例#6
0
class BlogPage(GrapplePageMixin, Page):
    author = models.CharField(max_length=255)
    date = models.DateField("Post date")
    advert = models.ForeignKey('home.Advert',
                               null=True,
                               blank=True,
                               on_delete=models.SET_NULL,
                               related_name='+')
    cover = models.ForeignKey('wagtailimages.Image',
                              null=True,
                              blank=True,
                              on_delete=models.SET_NULL,
                              related_name='+')
    book_file = models.ForeignKey('wagtaildocs.Document',
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL,
                                  related_name='+')
    featured_media = models.ForeignKey('wagtailmedia.Media',
                                       null=True,
                                       blank=True,
                                       on_delete=models.SET_NULL,
                                       related_name='+')
    body = StreamField([
        ("heading", blocks.CharBlock(classname="full title")),
        ("paraagraph", blocks.RichTextBlock()),
        ("image", ImageChooserBlock()),
        ("decimal", blocks.DecimalBlock()),
        ("date", blocks.DateBlock()),
        ("datetime", blocks.DateTimeBlock()),
    ])

    content_panels = Page.content_panels + [
        FieldPanel("author"),
        FieldPanel("date"),
        ImageChooserPanel('cover'),
        StreamFieldPanel("body"),
        InlinePanel('related_links', label="Related links"),
        SnippetChooserPanel('advert'),
        DocumentChooserPanel('book_file'),
        MediaChooserPanel('featured_media'),
    ]

    graphql_fields = [
        GraphQLString("heading"),
        GraphQLString("date"),
        GraphQLString("author"),
        GraphQLStreamfield("body"),
        GraphQLForeignKey("related_links", "home.blogpagerelatedlink", True),
        GraphQLSnippet('advert', 'home.Advert'),
        GraphQLImage('cover'),
        GraphQLDocument('book_file'),
        GraphQLMedia('featured_media'),
    ]
class InternationalTopicLandingPagePanels:

    content_panels = [
        FieldPanel('title'),
        FieldPanel('landing_page_title'),
        MultiFieldPanel(heading='Hero content',
                        children=[
                            ImageChooserPanel('hero_image'),
                            MediaChooserPanel('hero_video'),
                            FieldPanel('hero_teaser')
                        ]),
        MultiFieldPanel(
            heading="Explore more of the Investment Atlas section",
            classname="collapsible",
            children=[
                PageChooserPanel('related_page_one', [
                    'great_international.WhyInvestInTheUKPage',
                    'great_international.AboutUkRegionPage',
                    'great_international.InvestmentOpportunityPage',
                    'great_international.InvestmentGeneralContentPage',
                    'great_international.AboutUkRegionListingPage',
                    'great_international.InvestmentOpportunityListingPage'
                ]),
                PageChooserPanel('related_page_two', [
                    'great_international.WhyInvestInTheUKPage',
                    'great_international.AboutUkRegionPage',
                    'great_international.InvestmentOpportunityPage',
                    'great_international.InvestmentGeneralContentPage',
                    'great_international.AboutUkRegionListingPage',
                    'great_international.InvestmentOpportunityListingPage'
                ]),
                PageChooserPanel('related_page_three', [
                    'great_international.WhyInvestInTheUKPage',
                    'great_international.AboutUkRegionPage',
                    'great_international.InvestmentOpportunityPage',
                    'great_international.InvestmentGeneralContentPage',
                    'great_international.AboutUkRegionListingPage',
                    'great_international.InvestmentOpportunityListingPage'
                ]),
            ]),
        SearchEngineOptimisationPanel(),
    ]

    settings_panels = [
        FieldPanel('slug'),
        FieldPanel('tags', widget=CheckboxSelectMultiple)
    ]

    edit_handler = make_translated_interface(content_panels=content_panels,
                                             settings_panels=settings_panels)
示例#8
0
class TestPage(AbstractIonPage):
    document_field = models.ForeignKey(IonDocument, blank=True, null=True, on_delete=models.SET_NULL)
    image_field = models.ForeignKey(IonImage, blank=True, null=True, on_delete=models.SET_NULL)
    media_field = models.ForeignKey(IonMedia, blank=True, null=True, on_delete=models.SET_NULL)

    content_panels = AbstractIonPage.content_panels + [
        DocumentChooserPanel('document_field'),
        ImageChooserPanel('image_field'),
        MediaChooserPanel('media_field'),
    ]

    parent_page_types = [
        'IonLanguage',
        'TestPage',
    ]
class InternationalHomePagePanels:

    content_panels = [
        FieldPanel('title'),
        FieldPanel('hero_title'),
        MediaChooserPanel('hero_video'),
        StreamFieldPanel('homepage_link_panels'),
        SearchEngineOptimisationPanel(),
    ]

    settings_panels = [
        FieldPanel('slug'),
    ]

    edit_handler = make_translated_interface(content_panels=content_panels,
                                             settings_panels=settings_panels)
示例#10
0
class PodEpisodeBirdPage(Page, BirdMixin):
    body = StreamField([
        ('paragraph',
         blocks.RichTextBlock(
             required=False,
             null=True,
             features=[
                 'h2', 'h3', 'h4', 'bold', 'italic', 'superscript',
                 'subscript', 'strikethrough', 'ol', 'ul', 'hr', 'link',
                 'document-link', 'blockquote', 'embed', 'image'
             ])),
    ],
                       blank=True,
                       null=True)
    enclosure = models.ForeignKey('wagtailmedia.Media',
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL,
                                  related_name='+')
    enclosure_length = models.IntegerField(blank=True, null=True)
    enclosure_mime_type = models.CharField(max_length=50,
                                           blank=True,
                                           null=True)
    explicit = models.BooleanField(default=False)
    tags = ClusterTaggableManager(through=PodEpisodeBirdPageTag, blank=True)
    search_fields = Page.search_fields + BirdMixin.search_fields + [
        index.SearchField('body'),
    ]
    content_panels = Page.content_panels + BirdMixin.content_panels + [
        StreamFieldPanel('body'),
        MediaChooserPanel('enclosure'),
        FieldPanel('enclosure_length'),
        FieldPanel('enclosure_mime_type'),
    ]
    promote_panels = Page.promote_panels + [
        FieldPanel('tags'),
    ]
    settings_panels = Page.settings_panels + BirdMixin.settings_panels + [
        FieldPanel('explicit'),
    ]

    def get_sitemap_urls(self, request=None):
        if self.exclude_from_sitemap:
            return []
        else:
            return super(PodEpisodeBirdPage,
                         self).get_sitemap_urls(request=request)
示例#11
0
class EventPageRelatedMedia(Orderable):
    page = ParentalKey('wagtailmedia_tests.EventPage',
                       related_name='related_media',
                       on_delete=models.CASCADE)
    title = models.CharField(max_length=255, help_text="Link title")
    link_media = models.ForeignKey('wagtailmedia.Media',
                                   null=True,
                                   blank=True,
                                   related_name='+',
                                   on_delete=models.CASCADE)

    @property
    def link(self):
        return self.link_media.url

    panels = [
        FieldPanel('title'),
        MediaChooserPanel('link_media'),
    ]
示例#12
0
    def setUpTestData(cls):
        cls.request = RequestFactory().get("/")
        cls.request.user = (
            AnonymousUser()
        )  # technically, Anonymous users cannot access the admin

        fake_file = ContentFile("Test")
        fake_file.name = "test.mp3"

        cls.audio = Media.objects.create(
            title="Test audio", duration=1000, file=fake_file, type="audio"
        )

        fake_file = ContentFile("Test")
        fake_file.name = "test.mp4"

        cls.video = Media.objects.create(
            title="Test video", duration=1024, file=fake_file, type="video"
        )

        # a MediaChooserPanel class that works on BlogStreamPage's 'video' field
        cls.edit_handler = ObjectList([MediaChooserPanel("featured_media")]).bind_to(
            model=BlogStreamPage, request=cls.request
        )
        cls.my_media_chooser_panel = cls.edit_handler.children[0]

        # build a form class containing the fields that MyPageChooserPanel wants
        cls.MediaChooserForm = cls.edit_handler.get_form_class()

        root_page = Page.objects.first()
        cls.test_instance = BlogStreamPage(
            title="Post",
            slug="post",
            author="Joe Bloggs",
            date="1984-01-01",
            featured_media=cls.video,
        )
        root_page.add_child(instance=cls.test_instance)

        cls.form = cls.MediaChooserForm(instance=cls.test_instance)
        cls.media_chooser_panel = cls.my_media_chooser_panel.bind_to(
            instance=cls.test_instance, form=cls.form
        )
示例#13
0
class InvestmentGeneralContentPagePanels:
    content_panels = [
        MultiFieldPanel(
            heading="Hero and Intro",
            classname='collapsible',
            children=[
                FieldPanel('title'),
                ImageChooserPanel('hero_image'),
                MediaChooserPanel('hero_video'),
                FieldPanel('strapline'),
                FieldPanel('introduction'),
                ImageChooserPanel('intro_image'),
            ],
        ),
        StreamFieldPanel('main_content'),
        SearchEngineOptimisationPanel(),
    ]
    settings_panels = [
        FieldPanel('slug'),
    ]

    edit_handler = make_translated_interface(content_panels=content_panels,
                                             settings_panels=settings_panels)
示例#14
0
class InvestmentOpportunityListingPagePanels:

    content_panels = [
        MultiFieldPanel(
            heading='Opportunity Listing Page Title',
            children=[
                FieldPanel('title'),
                FieldPanel('search_results_title'),
                FieldPanel('breadcrumbs_label'),
            ],
        ),
        MultiFieldPanel(
            heading='Hero content',
            children=[
                MediaChooserPanel('hero_video'),
                FieldPanel('hero_text'),
            ],
        ),
        MultiFieldPanel(
            heading='CTA content',
            children=[
                FieldPanel('contact_cta_title'),
                FieldPanel('contact_cta_text'),
                FieldPanel('contact_cta_link'),
            ],
        ),
        SearchEngineOptimisationPanel(),
    ]
    settings_panels = [
        FieldPanel('slug'),
    ]

    edit_handler = make_translated_interface(
        content_panels=content_panels,
        settings_panels=settings_panels,
    )
class TranslationPage(Page):
    body = RichTextField(blank=True)
    author = models.CharField(max_length=100, blank=True, null=True)
    translators = models.CharField(max_length=100, blank=True, null=True)
    original_link = models.CharField(max_length=100, blank=True, null=True)
    rfatz_id = models.PositiveSmallIntegerField(null=True, blank=True)
    on_vk = models.BooleanField(default=False)
    readthesequences_link = models.CharField(max_length=100,
                                             blank=True,
                                             null=True)

    audio = models.ForeignKey('wagtailmedia.Media',
                              null=True,
                              blank=True,
                              on_delete=models.SET_NULL,
                              related_name='+')

    parent_page_types = [
        'translations.BookPage', 'translations.TranslationIndexPage'
    ]
    subpage_types = []

    content_panels = Page.content_panels + [
        FieldPanel('body', classname="full"),
        FieldPanel('author'),
        FieldPanel('translators'),
        FieldPanel('original_link'),
        FieldPanel('rfatz_id'),
        FieldPanel('on_vk'),
        FieldPanel('readthesequences_link'),
        MediaChooserPanel('audio'),
    ]

    def get_url_parts(self, *args, **kwargs):
        (site_id, root_url, _) = super().get_url_parts(*args, **kwargs)
        return (site_id, root_url, '/w/' + self.slug)
示例#16
0
class BlogStreamPage(Page):
    author = models.CharField(max_length=255)
    date = models.DateField("Post date")
    body = StreamField([
        ("heading", blocks.CharBlock(classname="full title", icon="title")),
        ("paragraph", blocks.RichTextBlock(icon="pilcrow")),
        ("media", TestMediaBlock(icon="media")),
        ("video", VideoChooserBlock(icon="media")),
        ("audio", AudioChooserBlock(icon="media")),
    ])

    featured_media = models.ForeignKey("wagtailmedia.Media",
                                       on_delete=models.PROTECT,
                                       related_name="+")

    content_panels = Page.content_panels + [
        FieldPanel("author"),
        FieldPanel("date"),
        StreamFieldPanel("body"),
        MediaChooserPanel("featured_media"),
        # the following are left here for local testing convenience
        # MediaChooserPanel("featured_media", media_type="audio"),
        # MediaChooserPanel("featured_media", media_type="video"),
    ]
示例#17
0
class InvestmentAtlasLandingPagePanels:

    content_panels = [
        MultiFieldPanel(heading="Title and breadcrumbs",
                        classname='collapsible',
                        children=[
                            FieldPanel('title'),
                            FieldPanel('breadcrumbs_label'),
                        ]),
        MultiFieldPanel(heading='Hero',
                        classname='collapsible',
                        children=[
                            ImageChooserPanel('hero_image'),
                            MediaChooserPanel('hero_video'),
                            ImageChooserPanel('mobile_hero_image'),
                            FieldPanel('hero_title'),
                            FieldPanel('hero_strapline'),
                        ]),
        MultiFieldPanel(
            heading='Downpage content panels',
            classname='collapsible',
            children=[
                StreamFieldPanel('downpage_sections'),
            ],
        ),
        SearchEngineOptimisationPanel(),
    ]

    settings_panels = [
        FieldPanel('slug'),
    ]

    edit_handler = make_translated_interface(
        content_panels=content_panels,
        settings_panels=settings_panels,
    )
示例#18
0
class HomePage(Page):
    #parent_page_types = [] # Nothing can have a homepage as a child

    video = models.ForeignKey('wagtailmedia.Media',
                              null=True,
                              blank=True,
                              on_delete=models.SET_NULL,
                              related_name='+')

    @property
    def feed_image(self):
        return self.hero.all()[0].background

    class Meta:
        verbose_name = 'Homepage'

    content_panels = Page.content_panels + [
        InlinePanel('hero', label='Hero'),
        InlinePanel('promo', label='Promo'),
        InlinePanel('featured', label='Featured'),
        MediaChooserPanel('video'),
    ]

    promote_panels = Page.promote_panels
示例#19
0
class ShortVideoPage(AllDotaPageMixin, LogoContainingPageMixin,
                     MetadataPageMixin, MultilingualPageMixin, Page):
    video = models.ForeignKey('wagtailmedia.Media',
                              null=True,
                              blank=False,
                              on_delete=models.SET_NULL,
                              related_name='+')

    video_thumbnail = models.ForeignKey('wagtailimages.Image',
                                        null=True,
                                        blank=True,
                                        on_delete=models.SET_NULL,
                                        related_name='+')

    @property
    def thumbnail(self):
        if self.video_thumbnail:
            return self.video_thumbnail
        else:
            return self.update_thumbnail()

    def update_thumbnail(self):
        generated_file = False
        if self.video.thumbnail:
            file = open(self.video.thumbnail.path, 'rb')
            file = File(file)
        else:
            clip = cv2.VideoCapture(self.video.file.path)
            ret, frame = clip.read()
            generated_file = 'thumbnail.jpeg'
            cv2.imwrite(generated_file, frame)
            file = open(generated_file, 'rb')
            file = File(file)
        thumbnail = Image(title=text_processing.html_to_str(
            self.english_title),
                          file=file)
        thumbnail.save()
        self.video_thumbnail = thumbnail
        self.save()
        if generated_file:
            os.remove(generated_file)
        return thumbnail

    english_title = RichTextField(features=[], blank=False, null=True)

    farsi_title = RichTextField(features=[],
                                blank=False,
                                null=True,
                                help_text='It has to start with a farsi word')

    english_caption = RichTextField(
        features=[],
        blank=False,
        null=True,
    )

    farsi_caption = RichTextField(
        features=[],
        blank=False,
        null=True,
        help_text='It has to start with a farsi word')

    english_tags = ClusterTaggableManager(through=ShortVideoPageEnglishTag,
                                          blank=True,
                                          related_name='english_tags')
    farsi_tags = ClusterTaggableManager(through=ShortVideoPageFarsiTag,
                                        blank=True,
                                        related_name='farsi_tags')

    content_panels = [
        MultiFieldPanel([
            MediaChooserPanel('video'),
        ],
                        heading='video',
                        classname='collapsible collapsed'),
        MultiFieldPanel([
            FieldPanel('farsi_title'),
            RichTextFieldPanel('farsi_caption'),
            FieldPanel('farsi_tags'),
        ],
                        heading='farsi',
                        classname='collapsible collapsed'),
        MultiFieldPanel([
            FieldPanel('english_title'),
            RichTextFieldPanel('english_caption'),
            FieldPanel('english_tags'),
        ],
                        heading='english',
                        classname='collapsible collapsed'),
    ]
    promote_panels = []
    settings_panels = []

    @property
    def farsi_url(self):
        return super().get_farsi_url()

    @property
    def english_url(self):
        return super().get_english_url()

    @property
    def template(self):
        return super().template

    @property
    def farsi_translated(self):
        return True

    @property
    def english_translated(self):
        return True

    def serve(self, request, *args, **kwargs):
        language = translation.get_language()
        if language == 'fa':
            self.search_description = text_processing.html_to_str(
                self.english_caption)
            self.seo_title = text_processing.html_to_str(self.english_title)
        else:
            self.search_description = text_processing.html_to_str(
                self.farsi_caption)
            self.seo_title = text_processing.html_to_str(self.farsi_title)
        return super().serve(request, *args, **kwargs)

    def clean(self):
        super().clean()
        if self.english_title:
            self.title = text_processing.html_to_str(self.english_title)
            pages = ShortVideoPage.objects.filter(title=self.title)
            if pages:
                if not self.id:
                    self.set_uuid4()
                    self.slug = slugify('{}_{}'.format(self.title, self.uuid4))
                else:
                    self.slug = slugify('{}_{}'.format(self.title, self.id))

    uuid4 = models.TextField(default='', blank=True)

    def set_uuid4(self):
        uuid4 = uuid.uuid4()
        while ShortVideoPage.objects.filter(uuid4=uuid4).exists():
            uuid4 = uuid.uuid4()
        self.uuid4 = str(uuid4)

    parent_page_types = ['home.ShortVideosPage']
    subpage_types = []

    def __str__(self):
        return self.english_title
示例#20
0
class ArticlePage(
        BasicPageAbstract,
        ContentPage,
        FeatureablePageAbstract,
        FromTheArchivesPageAbstract,
        ShareablePageAbstract,
        ThemeablePageAbstract,
):
    class ArticleTypes(models.TextChoices):
        CIGI_IN_THE_NEWS = ('cigi_in_the_news', 'CIGI in the News')
        INTERVIEW = ('interview', 'Interview')
        NEWS_RELEASE = ('news_release', 'News Release')
        OP_ED = ('op_ed', 'Op-Ed')
        OPINION = ('opinion', 'Opinion')

    class Languages(models.TextChoices):
        DA = ('da', 'Danish')
        DE = ('de', 'German')
        EL = ('el', 'Greek')
        EN = ('en', 'English')
        ES = ('es', 'Spanish')
        FR = ('fr', 'French')
        ID = ('id', 'Indonesian')
        IT = ('it', 'Italian')
        NL = ('nl', 'Dutch')
        PL = ('pl', 'Polish')
        PT = ('pt', 'Portugese')
        RO = ('ro', 'Romanian')
        SK = ('sk', 'Slovak')
        SV = ('sv', 'Swedish')
        TR = ('tr', 'Turkish')
        ZH = ('zh', 'Chinese')

    class HeroTitlePlacements(models.TextChoices):
        BOTTOM = ('bottom', 'Bottom')
        TOP = ('top', 'Top')

    article_series = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Opinion series',
    )
    article_type = models.ForeignKey(
        'articles.ArticleTypePage',
        null=True,
        blank=False,
        on_delete=models.SET_NULL,
        related_name='articles',
    )
    body = StreamField(
        BasicPageAbstract.body_default_blocks + [
            BasicPageAbstract.body_accordion_block,
            BasicPageAbstract.body_autoplay_video_block,
            BasicPageAbstract.body_chart_block,
            BasicPageAbstract.body_embedded_tiktok_block,
            BasicPageAbstract.body_external_quote_block,
            BasicPageAbstract.body_external_video_block,
            BasicPageAbstract.body_extract_block,
            BasicPageAbstract.body_highlight_title_block,
            BasicPageAbstract.body_image_full_bleed_block,
            BasicPageAbstract.body_image_scroll_block,
            BasicPageAbstract.body_poster_block,
            BasicPageAbstract.body_pull_quote_left_block,
            BasicPageAbstract.body_pull_quote_right_block,
            BasicPageAbstract.body_recommended_block,
            BasicPageAbstract.body_text_border_block,
            BasicPageAbstract.body_tool_tip_block,
            BasicPageAbstract.body_tweet_block,
        ],
        blank=True,
    )
    embed_youtube = models.URLField(
        blank=True,
        verbose_name='YouTube Embed',
        help_text=
        'Enter the YouTube URL (https://www.youtube.com/watch?v=4-Xkn1U1DkA) or short URL (https://youtu.be/o5acQ2GxKbQ) to add an embedded video.',
    )
    embed_youtube_label = models.CharField(
        max_length=255,
        blank=True,
        help_text='Add a label to appear below the embedded video.',
    )
    footnotes = RichTextField(
        blank=True,
        features=[
            'bold',
            'endofarticle',
            'h3',
            'h4',
            'italic',
            'link',
            'ol',
            'ul',
            'subscript',
            'superscript',
            'anchor',
        ],
    )
    hero_title_placement = models.CharField(
        blank=True,
        max_length=16,
        choices=HeroTitlePlacements.choices,
        verbose_name='Hero Title Placement',
        help_text=
        'Placement of the title within the hero section. Currently only works on the Longform 2 theme.',
    )
    hide_excerpt = models.BooleanField(
        default=False,
        verbose_name='Hide Excerpt',
        help_text=
        'For "CIGI in the News" only: when enabled, hide excerpt and display full article instead',
    )
    image_banner = models.ForeignKey(
        'images.CigionlineImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Banner Image',
    )
    image_banner_small = models.ForeignKey('images.CigionlineImage',
                                           null=True,
                                           blank=True,
                                           on_delete=models.SET_NULL,
                                           related_name='+',
                                           verbose_name='Banner Image Small')
    image_poster = models.ForeignKey(
        'images.CigionlineImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Poster Image',
        help_text='A poster image used in feature sections',
    )
    interviewers = StreamField(
        [
            ('interviewer',
             PageChooserBlock(required=True, page_type='people.PersonPage')),
        ],
        blank=True,
    )
    language = models.CharField(
        blank=True,
        max_length=2,
        choices=Languages.choices,
        verbose_name='Language',
        help_text=
        'If this content is in a language other than English, please select the language from the list.',
    )
    multimedia_series = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
    )
    related_files = StreamField(
        [
            ('file', DocumentChooserBlock()),
        ],
        blank=True,
    )
    short_description = RichTextField(
        blank=True,
        null=False,
        features=['bold', 'italic', 'link'],
    )
    video_banner = models.ForeignKey(
        'wagtailmedia.Media',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Banner Video',
    )
    website_button_text = models.CharField(
        blank=True,
        max_length=64,
        help_text=
        'Override the button text for the article website. If empty, the button will read "View Full Article".'
    )
    website_url = models.URLField(blank=True, max_length=512)
    works_cited = RichTextField(
        blank=True,
        features=[
            'bold',
            'endofarticle',
            'h3',
            'h4',
            'italic',
            'link',
            'ol',
            'ul',
            'subscript',
            'superscript',
        ],
    )

    # Reference field for the Drupal-Wagtail migrator. Can be removed after.
    drupal_node_id = models.IntegerField(blank=True, null=True)

    @property
    def cigi_people_mentioned_ids(self):
        return [item.person.id for item in self.cigi_people_mentioned.all()]

    @property
    def expired_image(self):
        if self.publishing_date:
            return self.publishing_date < datetime.datetime(
                2017, 1, 1).astimezone(pytz.timezone('America/Toronto'))
        return False

    @property
    def article_series_description(self):
        if self.article_series:
            return self.article_series.specific.series_items_description
        return None

    @property
    def article_series_disclaimer(self):
        if self.article_series:
            for series_item in self.article_series.specific.article_series_items:
                if series_item.content_page.specific == self and not series_item.hide_series_disclaimer:
                    return self.article_series.specific.series_items_disclaimer
        return None

    def is_opinion(self):
        return self.article_type.title in [
            'Op-Eds',
            'Opinion',
        ]

    def get_template(self, request, *args, **kwargs):
        standard_template = super(ArticlePage,
                                  self).get_template(request, *args, **kwargs)
        if self.theme:
            return f'themes/{self.get_theme_dir()}/article_page.html'
        return standard_template

    content_panels = [
        BasicPageAbstract.title_panel,
        MultiFieldPanel([
            FieldPanel('short_description'),
            StreamFieldPanel('body'),
            FieldPanel('footnotes'),
            FieldPanel('works_cited'),
        ],
                        heading='Body',
                        classname='collapsible collapsed'),
        MultiFieldPanel(
            [
                PageChooserPanel(
                    'article_type',
                    ['articles.ArticleTypePage'],
                ),
                FieldPanel('hide_excerpt'),
                FieldPanel('publishing_date'),
                FieldPanel('website_url'),
                FieldPanel('website_button_text'),
                FieldPanel('language'),
            ],
            heading='General Information',
            classname='collapsible collapsed',
        ),
        ContentPage.authors_panel,
        MultiFieldPanel(
            [
                ImageChooserPanel('image_hero'),
                ImageChooserPanel('image_poster'),
                ImageChooserPanel('image_banner'),
                ImageChooserPanel('image_banner_small'),
            ],
            heading='Images',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                FieldPanel('embed_youtube'),
                FieldPanel('embed_youtube_label'),
                MediaChooserPanel('video_banner'),
            ],
            heading='Media',
            classname='collapsible collapsed',
        ),
        ContentPage.recommended_panel,
        MultiFieldPanel(
            [
                FieldPanel('topics'),
                FieldPanel('projects'),
                PageChooserPanel(
                    'article_series',
                    ['articles.ArticleSeriesPage'],
                ),
                PageChooserPanel(
                    'multimedia_series',
                    ['multimedia.MultimediaSeriesPage'],
                ),
                InlinePanel('cigi_people_mentioned', label='People Mentioned'),
                StreamFieldPanel('interviewers'),
                StreamFieldPanel('related_files'),
            ],
            heading='Related',
            classname='collapsible collapsed',
        ),
        FromTheArchivesPageAbstract.from_the_archives_panel,
    ]
    promote_panels = Page.promote_panels + [
        FeatureablePageAbstract.feature_panel,
        ShareablePageAbstract.social_panel,
        SearchablePageAbstract.search_panel,
    ]
    settings_panels = Page.settings_panels + [
        ThemeablePageAbstract.theme_panel,
    ]

    search_fields = BasicPageAbstract.search_fields \
        + ContentPage.search_fields \
        + [
            index.FilterField('article_type'),
            index.FilterField('cigi_people_mentioned_ids'),
            index.FilterField('publishing_date'),
        ]

    parent_page_types = ['articles.ArticleListPage']
    subpage_types = []
    templates = 'articles/article_page.html'

    @property
    def is_title_bottom(self):
        return self.title in [
            'Can the G20 Save Globalization\'s Waning Reputation?',
            'Shoshana Zuboff on the Undetectable, Indecipherable World of Surveillance Capitalism'
        ]

    @property
    def article_series_category(self):
        category = ''
        for series_item in self.article_series.specific.article_series_items:
            if series_item.category_title:
                category = series_item.category_title
            if series_item.content_page.id == self.id:
                return category

    class Meta:
        verbose_name = 'Opinion'
        verbose_name_plural = 'Opinions'
示例#21
0
class BlogPage(HeadlessPreviewMixin, Page):
    date = models.DateField("Post date")
    advert = models.ForeignKey(
        "home.Advert",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    cover = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    book_file = models.ForeignKey(
        "wagtaildocs.Document",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    featured_media = models.ForeignKey(
        "wagtailmedia.Media",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    author = models.ForeignKey(AuthorPage,
                               null=True,
                               blank=True,
                               on_delete=models.SET_NULL,
                               related_name="+")
    body = StreamField(StreamFieldBlock())

    content_panels = Page.content_panels + [
        FieldPanel("date"),
        ImageChooserPanel("cover"),
        StreamFieldPanel("body"),
        InlinePanel("related_links", label="Related links"),
        InlinePanel("authors", label="Authors"),
        FieldPanel("author"),
        SnippetChooserPanel("advert"),
        DocumentChooserPanel("book_file"),
        MediaChooserPanel("featured_media"),
    ]

    @property
    def copy(self):
        return self

    graphql_fields = [
        GraphQLString("heading"),
        GraphQLString("date", required=True),
        GraphQLStreamfield("body"),
        GraphQLCollection(GraphQLForeignKey,
                          "related_links",
                          "home.blogpagerelatedlink",
                          required=True,
                          item_required=True),
        GraphQLCollection(GraphQLString,
                          "related_urls",
                          source="related_links.url"),
        GraphQLCollection(GraphQLString,
                          "authors",
                          source="authors.person.name"),
        GraphQLSnippet("advert", "home.Advert"),
        GraphQLImage("cover"),
        GraphQLDocument("book_file"),
        GraphQLMedia("featured_media"),
        GraphQLForeignKey("copy", "home.BlogPage"),
        GraphQLPage("author"),
    ]
示例#22
0
class Banner(Orderable):
    page = ParentalKey(
        'HomePage',
        related_name='banners',
        on_delete=models.CASCADE,
        blank=False,
    )

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

    video = models.ForeignKey(
        'wagtailmedia.Media',
        help_text=_("""Banner video media. If video is not supported by the
        browser, the image is shown instead."""),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+')

    title_en = models.CharField(
        max_length=255,
        verbose_name=_('English banner title'),
        help_text=_('Enter the title to be shown on the banner.'),
        blank=True,
    )

    title_sv = models.CharField(
        max_length=255,
        verbose_name=_('Swedish banner title'),
        help_text=_('Enter the title to be shown on the banner.'),
        blank=True,
    )

    title = TranslatedField('title_en', 'title_sv')

    text_en = models.TextField(
        verbose_name=_('English banner text'),
        help_text=_('Enter a text to be shown on the banner.'),
        blank=True,
    )

    text_sv = models.TextField(
        verbose_name=_('Swedish banner text'),
        help_text=_('Enter a text to be shown on the banner.'),
        blank=True,
    )

    text = TranslatedField('text_en', 'text_sv')

    link = models.URLField(
        verbose_name=_('Button URL'),
        blank=True,
    )

    button_en = models.TextField(
        verbose_name=_('English button text'),
        help_text=_('Enter the text to be displayed on the button.'),
        blank=True,
    )

    button_sv = models.TextField(
        verbose_name=_('Swedish button text'),
        help_text=_('Enter the text to be displayed on the button.'),
        blank=True,
    )

    button = TranslatedField('button_en', 'button_sv')

    # ------ Administrator settings ------
    panels = [
        MultiFieldPanel([
            ImageChooserPanel('image'),
            MediaChooserPanel('video'),
            FieldRowPanel([
                FieldPanel('title_en'),
                FieldPanel('title_sv'),
            ]),
            FieldPanel('text_en'),
            FieldPanel('text_sv'),
            FieldPanel('link'),
            FieldRowPanel([
                FieldPanel('button_en'),
                FieldPanel('button_sv'),
            ]),
        ])
    ]
示例#23
0
class ArticleSeriesPage(
        BasicPageAbstract,
        ContentPage,
        FeatureablePageAbstract,
        FromTheArchivesPageAbstract,
        ShareablePageAbstract,
        ThemeablePageAbstract,
):
    credits = RichTextField(
        blank=True,
        features=[
            'bold',
            'italic',
            'link',
            'name',
        ],
    )
    credits_stream_field = StreamField(
        [('title',
          StructBlock([
              ('title', CharBlock()),
              ('people', StreamBlock([('name', CharBlock())])),
          ]))],
        blank=True,
    )
    credits_artwork = models.CharField(
        max_length=255,
        blank=True,
    )
    featured_items = StreamField(
        [
            ('featured_item',
             PageChooserBlock(
                 required=True,
                 page_type=[
                     'articles.ArticlePage', 'multimedia.MultimediaPage'
                 ],
             )),
        ],
        blank=True,
    )
    image_banner = models.ForeignKey(
        'images.CigionlineImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Banner Image',
    )
    image_banner_small = models.ForeignKey('images.CigionlineImage',
                                           null=True,
                                           blank=True,
                                           on_delete=models.SET_NULL,
                                           related_name='+',
                                           verbose_name='Banner Image Small')
    image_poster = models.ForeignKey(
        'images.CigionlineImage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Poster image',
        help_text=
        'A poster image which will be used in the highlights section of the homepage.',
    )
    short_description = RichTextField(
        blank=True,
        null=False,
        features=['bold', 'italic', 'link'],
    )
    series_items_description = RichTextField(
        blank=True,
        null=True,
        features=['bold', 'italic', 'link'],
    )
    series_videos_description = RichTextField(
        blank=True,
        null=True,
        features=['bold', 'italic', 'link'],
        help_text=
        'To be displayed on video/multimedia pages of the series in place of Series Items Description'
    )
    series_items_disclaimer = RichTextField(
        blank=True,
        null=True,
        features=['bold', 'italic', 'link'],
    )
    video_banner = models.ForeignKey(
        'wagtailmedia.Media',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name='Banner Video',
    )

    @property
    def image_poster_caption(self):
        return self.image_poster.caption

    @property
    def image_poster_url(self):
        return self.image_poster.get_rendition('fill-672x895').url

    @property
    def article_series_items(self):
        return self.series_items.prefetch_related(
            'content_page',
            'content_page__authors__author',
        ).all()

    # Reference field for the Drupal-Wagtail migrator. Can be removed after.
    drupal_node_id = models.IntegerField(blank=True, null=True)

    def get_template(self, request, *args, **kwargs):
        standard_template = super(ArticleSeriesPage,
                                  self).get_template(request, *args, **kwargs)
        if self.theme:
            return f'themes/{self.get_theme_dir()}/article_series_page.html'
        return standard_template

    content_panels = [
        BasicPageAbstract.title_panel,
        MultiFieldPanel(
            [
                FieldPanel('short_description'),
                StreamFieldPanel('body'),
            ],
            heading='Body',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                FieldPanel('publishing_date'),
            ],
            heading='General Information',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                FieldPanel('series_items_description'),
                FieldPanel('series_videos_description'),
                FieldPanel('series_items_disclaimer'),
                InlinePanel('series_items'),
            ],
            heading='Series Items',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                FieldPanel('credits'),
                FieldPanel('credits_artwork'),
                StreamFieldPanel('credits_stream_field'),
            ],
            heading='Credits',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                ImageChooserPanel('image_hero'),
                ImageChooserPanel('image_banner'),
                ImageChooserPanel('image_banner_small'),
                ImageChooserPanel('image_poster'),
            ],
            heading='Image',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                MediaChooserPanel('video_banner'),
            ],
            heading='Media',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                StreamFieldPanel('featured_items'),
            ],
            heading='Featured Series Items',
            classname='collapsible collapsed',
        ),
        MultiFieldPanel(
            [
                FieldPanel('topics'),
            ],
            heading='Related',
            classname='collapsible collapsed',
        ),
    ]

    promote_panels = Page.promote_panels + [
        FeatureablePageAbstract.feature_panel,
        ShareablePageAbstract.social_panel,
        SearchablePageAbstract.search_panel,
    ]

    settings_panels = Page.settings_panels + [
        ThemeablePageAbstract.theme_panel,
    ]

    search_fields = Page.search_fields \
        + BasicPageAbstract.search_fields \
        + ContentPage.search_fields

    parent_page_types = ['home.HomePage']
    subpage_types = []
    templates = 'articles/article_series_page.html'

    @property
    def series_contributors_by_article(self):
        series_contributors = []
        item_people = set()

        for series_item in self.article_series_items:
            people = series_item.content_page.authors.all()
            people_string = ''

            for person in people:
                person_string = person.author.title
                people_string += person_string

                # Add each person as well so if there's an article with just
                # a single author who's already been in another article in
                # collaboration, then we won't add their name to the list
                # again.
                if len(people) > 1:
                    item_people.add(person_string)

            if people_string not in item_people:
                series_contributors.append({
                    'item': series_item.content_page,
                    'contributors': people
                })
                item_people.add(people_string)

        return series_contributors

    @property
    def series_contributors(self):
        series_contributors = []
        item_people = set()

        for series_item in self.article_series_items:
            people = series_item.content_page.authors.all()
            for person in people:
                if person.author.title not in item_people:
                    series_contributors.append({
                        'id': person.author.id,
                        'title': person.author.title,
                        'url': person.author.url,
                    })
                    item_people.add(person.author.title)
        return series_contributors

    @property
    def series_contributors_by_person(self):
        # Series contributors ordered by last name
        series_contributors = []
        item_people = set()

        for series_item in self.article_series_items:
            people = series_item.content_page.authors.all()

            # Skip items that have more than 2 authors/speakers. For
            # example, in the After COVID series, there is an introductory
            # video with many authors.
            if len(people) > 2:
                continue
            else:
                for person in people:
                    if person.author.title not in item_people:
                        series_contributors.append({
                            'item':
                            series_item.content_page,
                            'contributors': [person.author],
                            'last_name':
                            person.author.last_name,
                        })
                        item_people.add(person.author.title)

        series_contributors.sort(key=lambda x: x['last_name'])
        return series_contributors

    @property
    def series_authors(self):
        series_authors = []
        series_people = set()
        for series_item in self.article_series_items:
            people = series_item.content_page.authors.all()
            for person in people:
                if person.author.title not in series_people:
                    series_authors.append(person.author)
                    series_people.add(person.author.title)
        return series_authors

    class Meta:
        verbose_name = 'Opinion Series'
        verbose_name_plural = 'Opinion Series'
示例#24
0
class InvestmentOpportunityPagePanels:

    content_panels = [
        MultiFieldPanel(
            heading='Opportunity Page title, intro and summary',
            classname='collapsible',
            children=[
                FieldPanel('title'),
                FieldPanel('breadcrumbs_label'),
                ImageChooserPanel('hero_image'),
                MediaChooserPanel('hero_video'),
                FieldPanel('strapline'),
                FieldPanel('introduction'),
                ImageChooserPanel('intro_image'),
                FieldPanel('opportunity_summary'),
            ],
        ),
        MultiFieldPanel(
            heading="Key facts",
            classname='collapsible',
            children=[
                FieldRowPanel([
                    FieldPanel('promoter'),
                    FieldPanel('location'),
                    MultiFieldPanel(heading='Scale',
                                    children=[
                                        FieldPanel('scale'),
                                        FieldPanel('scale_value'),
                                    ]),
                ]),
                FieldRowPanel([
                    FieldPanel('planning_status'),
                    FieldPanel('investment_type'),
                    FieldPanel('time_to_investment_decision'),
                ]),
                HelpPanel(
                    'In addition to these, please also set a location in the Location tab'
                ),
            ],
        ),
        MultiFieldPanel(
            heading='Opportunity Contact',
            classname='collapsible',
            children=[
                FieldPanel('contact_name'),
                ImageChooserPanel('contact_avatar'),
                FieldPanel('contact_job_title'),
                FieldPanel('contact_link'),
            ],
        ),
        MultiFieldPanel(
            heading='The Opportunity',
            classname='collapsible',
            children=[
                StreamFieldPanel('main_content'),
                FieldPanel('important_links'),
            ],
        ),
        SearchEngineOptimisationPanel(),
    ]

    related_entities_panels = [
        FieldRowPanel(heading='Location and Relevant Regions',
                      classname='collapsible',
                      children=[
                          StreamFieldPanel('regions_with_locations'),
                      ]),
        FieldRowPanel(
            heading="Sectors and Sub-sectors",
            classname='collapsible collapsed',
            children=[
                InlinePanel('related_sectors', label="Related Sectors"),
                InlinePanel('related_sub_sectors', label="Related Sub-sectors")
            ],
        ),
    ]

    settings_panels = [
        FieldPanel('slug'),
        FieldPanel('priority_weighting'),
    ]

    edit_handler = make_translated_interface(
        content_panels=content_panels,
        other_panels=related_entities_panels,  # These are shown as separate tabs
        settings_panels=settings_panels,
    )
示例#25
0
class HeroVideoFields(models.Model):
    hero_video = models.ForeignKey(
        'utils.CustomMedia',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        help_text=
        "Short Hero Video to show on top of page. Recommended size 12Mb or under.",
        related_name='+')
    hero_fallback_image = models.ForeignKey(
        'images.CustomImage',
        null=True,
        blank=True,
        related_name='+',
        help_text="Hero Image to be used as fallback for video.",
        on_delete=models.SET_NULL)
    hero_strapline = models.TextField(
        blank=True,
        max_length=255,
        help_text=
        "Shows text over the hero. If no strapline is entered, no page title will show."
    )
    hero_strapline_hex = models.CharField(
        blank=True,
        max_length=7,
        help_text="Add valid hex to change colour of strapline.")

    link_page = models.ForeignKey(
        Page,
        blank=True,
        null=True,
        related_name='+',
        on_delete=models.SET_NULL,
        help_text="Optional page link as clickthrough for hero video.",
        verbose_name="Page Link")
    link_youtube = models.URLField(
        blank=True,
        help_text="Optional URL for a full length YouTube video goes here,\
                    which will open in a modal window.",
        verbose_name="YouTube Link")
    link_text = models.CharField(blank=True, max_length=255)

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

    content_panels = [
        MultiFieldPanel([
            MediaChooserPanel('hero_video'),
            ImageChooserPanel('hero_fallback_image'),
            FieldPanel('hero_strapline'),
            FieldPanel('hero_strapline_hex'),
            MultiFieldPanel([
                PageChooserPanel('link_page'),
                FieldPanel('link_youtube'),
                FieldPanel('link_text'),
            ], 'Hero Clickthrough Link')
        ], 'Hero Video'),
    ]

    def clean(self):
        from girleffect.utils.blocks import validate_hex

        if self.hero_strapline_hex:
            if not validate_hex(self.hero_strapline_hex):
                raise ValidationError(
                    {'hero_strapline_hex': _('Please enter a valid hex code')})

        # Validating if URL is a valid YouTube URL
        youtube_embed = self.link_youtube
        if youtube_embed:
            youtube_finder = OEmbedFinder(providers=[oembed_providers.youtube])
            if not youtube_finder.accept(youtube_embed):
                raise ValidationError(
                    {'link_youtube': _('Please supply a valid YouTube URL.')})
            else:
                try:
                    embed = get_embed(youtube_embed)
                    self.link_youtube_html = embed.html
                except EmbedException:
                    raise ValidationError(
                        {'link_youtube': _('Embed cannot be found.')})

        # Validating links
        populated_fields = []

        for link_field in [self.link_page, self.link_youtube]:
            if link_field:
                populated_fields.append(link_field)

        # Only only one or less fields can be selected
        if len(populated_fields) > 1:
            error_message = 'Please choose only one of Link Page or Link YouTube as destination.'
            raise ValidationError({
                'link_page': error_message,
                'link_youtube': error_message
            })

        # Link fields should have link text
        if len(populated_fields) >= 1 and not self.link_text:
            raise ValidationError({
                'link_text':
                'Link text is required if link destination has been selected'
            })

        return super(HeroVideoFields, self).clean()

    class Meta:
        abstract = True
示例#26
0
class BlogPage(HeadlessPreviewMixin, Page):
    date = models.DateField("Post date")
    advert = models.ForeignKey(
        "home.Advert",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    hero_image = models.ForeignKey(
        "images.CustomImage",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    book_file = models.ForeignKey(
        "wagtaildocs.Document",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    featured_media = models.ForeignKey(
        "wagtailmedia.Media",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    author = models.ForeignKey(AuthorPage,
                               null=True,
                               blank=True,
                               on_delete=models.SET_NULL,
                               related_name="+")
    body = StreamField(StreamFieldBlock())
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)

    content_panels = Page.content_panels + [
        FieldPanel("date"),
        ImageChooserPanel("hero_image"),
        StreamFieldPanel("body"),
        FieldPanel("tags"),
        InlinePanel("related_links", label="Related links"),
        InlinePanel("authors", label="Authors"),
        FieldPanel("author"),
        SnippetChooserPanel("advert"),
        DocumentChooserPanel("book_file"),
        MediaChooserPanel("featured_media"),
    ]

    @property
    def copy(self):
        return self

    def paginated_authors(self, info, **kwargs):
        return resolve_paginated_queryset(self.authors, info, **kwargs)

    graphql_fields = [
        GraphQLString("date", required=True),
        GraphQLStreamfield("body"),
        GraphQLTag("tags"),
        GraphQLCollection(
            GraphQLForeignKey,
            "related_links",
            "home.blogpagerelatedlink",
            required=True,
            item_required=True,
        ),
        GraphQLCollection(GraphQLString,
                          "related_urls",
                          source="related_links.url"),
        GraphQLCollection(GraphQLString,
                          "authors",
                          source="authors.person.name"),
        GraphQLCollection(
            GraphQLForeignKey,
            "paginated_authors",
            "home.Author",
            is_paginated_queryset=True,
        ),
        GraphQLSnippet("advert", "home.Advert"),
        GraphQLImage("hero_image"),
        GraphQLDocument("book_file"),
        GraphQLMedia("featured_media"),
        GraphQLForeignKey("copy", "home.BlogPage"),
        GraphQLPage("author"),
    ]
class InternationalInvestmentSectorPagePanels:
    content_panels = [
        FieldPanel('title'),
        MultiFieldPanel(heading='Heading',
                        classname='collapsible',
                        children=[
                            FieldPanel('heading'),
                            ImageChooserPanel('hero_image'),
                            MediaChooserPanel('hero_video'),
                            FieldPanel('standfirst'),
                            FieldPanel('featured_description')
                        ]),
        MultiFieldPanel(heading='Intro',
                        classname='collapsible',
                        children=[
                            FieldPanel('intro_text'),
                            ImageChooserPanel('intro_image'),
                        ]),
        MultiFieldPanel(heading='Contact details',
                        classname='collapsible',
                        children=[
                            FieldPanel('contact_name'),
                            ImageChooserPanel('contact_avatar'),
                            FieldPanel('contact_job_title'),
                            FieldPanel('contact_link'),
                            FieldPanel('contact_link_button_preamble'),
                            FieldPanel('contact_link_button_label'),
                        ]),
        MultiFieldPanel(
            heading='Related opportunities',
            classname='collapsible',
            children=[
                FieldPanel('related_opportunities_header'),
                HelpPanel(
                    'See the dedicated tab for selecting the opportunities themselves'
                ),
            ]),
        StreamFieldPanel('downpage_content'),
        MultiFieldPanel(heading='Early opportunities',
                        classname='collapsible',
                        children=[
                            FieldPanel('early_opportunities_header'),
                            StreamFieldPanel('early_opportunities'),
                        ]),
        SearchEngineOptimisationPanel()
    ]

    settings_panels = [
        FieldPanel('slug'),
        FieldPanel('tags'),
    ]

    related_entities_panels = [
        FieldRowPanel(
            heading='Related Opportunities',
            children=[
                StreamFieldPanel('manually_selected_related_opportunities'),
            ]),
    ]

    edit_handler = make_translated_interface(
        content_panels=content_panels,
        other_panels=related_entities_panels,  # These are shown as separate tabs
        settings_panels=settings_panels)