Exemplo n.º 1
0
class BlogPage(Page):
    body = StreamField(STANDARD_BLOCKS)
    tags = ClusterTaggableManager(through='blog.BlogPageTag', blank=True)
    date = models.DateField(
        _("Post date"),
        default=datetime.datetime.today,
        help_text=_("This date may be displayed on the blog post. It is not "
                    "used to schedule posts to go live at a later date."))
    header_image = models.ForeignKey(get_image_model_string(),
                                     null=True,
                                     blank=True,
                                     on_delete=models.SET_NULL,
                                     related_name='+',
                                     verbose_name=_('Header Image'))
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=True,
        null=True,
        limit_choices_to=limit_author_choices,
        verbose_name=_('Author'),
        on_delete=models.SET_NULL,
        related_name='author_pages',
    )

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

    blog_categories = models.ManyToManyField(
        'blog.BlogCategory', through='blog.BlogCategoryBlogPage', blank=True)

    settings_panels = [
        MultiFieldPanel([
            FieldRowPanel([
                FieldPanel('go_live_at'),
                FieldPanel('expire_at'),
            ],
                          classname="label-above"),
        ],
                        'Scheduled publishing',
                        classname="publishing"),
        FieldPanel('date'),
        FieldPanel('author'),
    ]

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

    def save_revision(self, *args, **kwargs):
        if not self.author:
            self.author = self.owner
        return super(BlogPage, self).save_revision(*args, **kwargs)

    def get_absolute_url(self):
        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'] = settings.COMMENTS_APP
        return context

    class Meta:
        verbose_name = _('Blog Page')
        verbose_name_plural = _('Blog Pages')

    parent_page_types = ['blog.BlogIndexPage']
Exemplo n.º 2
0
class GeneralShelvePage(Page):
    release = models.ForeignKey(
        'release.Release',
        related_name='%(class)s_pages',
        blank=True,
        null=True,
        default=None,
        on_delete=models.SET_NULL,
        limit_choices_to={'content_status': CONTENT_STATUS_PENDING})

    page_theme = models.ForeignKey(Theme,
                                   related_name='%(class)s_pages',
                                   null=True,
                                   on_delete=models.SET_NULL,
                                   verbose_name='theme')

    hide_from_breadcrumb = models.BooleanField(default=False)

    @property
    def og_image(self):
        try:
            return self.og_image_fk.file.url
        except AttributeError:
            pass
        except ValueError:
            pass
        return ''

    @property
    def twitter_image(self):
        try:
            return self.twitter_image_fk.file.url
        except AttributeError:
            pass
        except ValueError:
            pass
        return ''

    @property
    def theme(self):
        return self.page_theme.to_dict()

    @property
    def link_url(self):
        # TODO: This could potentially use some base page methods
        import re
        url_path = self.url_path
        # Remove homepage slug from url_path
        site_settings = SiteSettings.objects.get(site=self.get_site())
        homepage_slug_path = site_settings.site.root_page.slug
        regexp = r'/{0}(/.*)'.format(homepage_slug_path)
        matchObj = re.match(regexp, self.url_path)
        if matchObj:
            url_path = matchObj.group(1)
        return '/' + site_settings.uid + url_path

    @property
    def breadcrumbs(self):
        ancestors = self.get_ancestors().live()[1:]
        breadcrumbs = []
        for ancestor in ancestors:
            # If root page it doesn't have link url
            try:
                breadcrumbs.append({
                    'name':
                    ancestor.specific.seo_title or ancestor.specific.title,
                    'url':
                    ancestor.specific.link_url,
                    'visible':
                    not ancestor.specific.hide_from_breadcrumb,
                })
            except AttributeError:
                site_name = SiteSettings.objects.get(site=self.get_site()).uid
                breadcrumbs.append({
                    'name':
                    ancestor.specific.seo_title or ancestor.specific.title,
                    'url':
                    '/' + site_name,
                    'visible':
                    True,
                })
        return breadcrumbs

    content_panels = Page.content_panels + [
        StreamFieldPanel('body'),
        FieldPanel('release'),
        SnippetChooserPanel('page_theme'),
    ]

    info_content_panels = [
        InlinePanel('change_history', label='Change history'),
    ]

    meta_content_panels = [
        MultiFieldPanel([
            FieldPanel('og_title'),
            FieldPanel('og_description'),
            FieldPanel('og_url'),
            ImageChooserPanel('og_image_fk'),
            FieldPanel('og_type'),
        ],
                        heading='Open Graph Tags',
                        classname='collapsible collapsed'),
        MultiFieldPanel([
            FieldPanel('twitter_url'),
            FieldPanel('twitter_card'),
            FieldPanel('twitter_site'),
            FieldPanel('twitter_title'),
            FieldPanel('twitter_description'),
            ImageChooserPanel('twitter_image_fk'),
        ],
                        heading='Twitter Tags',
                        classname='collapsible collapsed'),
        MultiFieldPanel([
            FieldPanel('use_share_button'),
            FieldPanel('use_email_button'),
            FieldPanel('use_print_button'),
        ],
                        heading='Share buttons',
                        classname='collapsible collapsed'),
        MultiFieldPanel([
            FieldPanel('tracking_group'),
        ],
                        heading='Tracking',
                        classname='collapsible collapsed'),
    ]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel('slug'),
                FieldPanel('seo_title'),
                FieldPanel('show_in_menus'),
                FieldPanel('search_description'),
                FieldPanel('hide_from_breadcrumb'),
            ],
            heading='Common page configuration',
        )
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(info_content_panels, heading='Notes'),
        ObjectList(meta_content_panels, heading='Meta'),
        ObjectList(promote_panels, heading='Settings'),
    ])

    api_fields = ['body', 'path', 'depth', 'numchild', 'live', 'theme']
    exclude_fields_in_copy = ['release']

    class Meta:
        abstract = True

    @classmethod
    def get_serializer(cls):
        import importlib
        app = cls.__module__.rsplit('.', 1)[0]
        module = '{}.serializers'.format(app)
        serializer_name = '{}Serializer'.format(cls.__name__)
        serializers_module = importlib.import_module(module)
        serializer = getattr(serializers_module, serializer_name)
        return serializer

    @classmethod
    def create_from_dict(cls, obj_dict):
        return cls(title=obj_dict['title'],
                   path=obj_dict['path'],
                   depth=obj_dict['depth'],
                   numchild=obj_dict['numchild'],
                   slug=obj_dict['meta']['slug'],
                   seo_title=obj_dict['meta']['seo_title'],
                   show_in_menus=obj_dict['meta']['show_in_menus'],
                   search_description=obj_dict['meta']['search_description'],
                   first_published_at=obj_dict['meta']['first_published_at'],
                   body=json.dumps(obj_dict['body']),
                   live=obj_dict['live'],
                   page_theme_id=obj_dict['theme']['id'])

    def update_from_dict(self, obj_dict, default_excludes=None, excludes=None):
        if not default_excludes:
            class_ptr_id = '{}_ptr_id'.format(t.__class__.__name__.lower())
            default_excludes = [
                'id', 'path', 'depth', 'numchild', 'content_type_id',
                'live_revision_id', 'page_ptr_id', class_ptr_id, 'release_id',
                'live', 'locked', 'url_path'
            ]
        if not excludes:
            excludes = []

        excludes = default_excludes + excludes
        for key, value in obj_dict.items():
            if key not in excludes and not key.startswith('_'):
                setattr(self, key, value)
        return self

    def serializable_data(self):
        obj = get_serializable_data_for_fields(self)

        for rel in get_all_child_relations(self):
            rel_name = rel.get_accessor_name()
            children = getattr(self, rel_name).all()

            if hasattr(rel.related_model, 'serializable_data'):
                obj[rel_name] = [
                    child.serializable_data() for child in children
                ]
            else:
                obj[rel_name] = [
                    get_serializable_data_for_fields(child)
                    for child in children
                ]

        for field in get_all_child_m2m_relations(self):
            children = getattr(self, field.name).all()
            obj[field.name] = [child.pk for child in children]

        return obj

    def save_revision(self,
                      user=None,
                      submitted_for_moderation=False,
                      approved_go_live_at=None,
                      changed=True):
        assigned_release = self.release
        self.release = None
        revision = super(GeneralShelvePage,
                         self).save_revision(user, submitted_for_moderation,
                                             approved_go_live_at, changed)

        if assigned_release:
            from release.models import ReleasePage
            if submitted_for_moderation:
                ReleasePage.submit_for_moderation(revision, assigned_release)
            else:
                assigned_release.add_revision(revision)

        return revision

    def unpublish(self, release_id=None):
        if not release_id:
            pass
        else:
            from release.models import Release
            try:
                release = Release.objects.get(id=release_id)
                release.remove_page(self.id)
            except Release.DoesNotExist:
                pass

    def serve_preview(self,
                      request,
                      mode_name,
                      site_name,
                      revision_id='latest'):
        request.is_preview = True

        if mode_name == 'json':
            Serializer = self.__class__.get_serializer()
            latest_revision_as_page = self.get_latest_revision_as_page()
            serialized_page = Serializer(instance=latest_revision_as_page)
            return JsonResponse(serialized_page.data)

        if mode_name == 'react':
            path = self.get_url_parts(request)[2] if self.get_url_parts(
                request) is not None else '/home'
            context = {
                'preview_url':
                '/{}{}?is_preview&revision={}'.format(site_name, path,
                                                      revision_id)
            }
            return SimpleTemplateResponse(template='preview_wrapper.html',
                                          context=context)

        return self.serve(request)

    def serializable_data(self):
        obj = get_serializable_data_for_fields(self)

        for rel in get_all_child_relations(self):
            rel_name = rel.get_accessor_name()
            children = getattr(self, rel_name).all()

            if hasattr(rel.related_model, 'serializable_data'):
                obj[rel_name] = [
                    child.serializable_data() for child in children
                ]
            else:
                obj[rel_name] = [
                    get_serializable_data_for_fields(child)
                    for child in children
                ]

        for field in get_all_child_m2m_relations(self):
            children = getattr(self, field.name).all()
            obj[field.name] = [child.pk for child in children]

        return obj

    def serve(self, request, *args, **kwargs):
        request.is_preview = getattr(request, 'is_preview', False)

        return TemplateResponse(request,
                                self.get_template(request, *args, **kwargs),
                                self.get_context(request, *args, **kwargs))

    DEFAULT_PREVIEW_MODES = [
        ('react', 'Default'),
        # ('html', 'AMP'),
        ('json', 'API'),
    ]

    @property
    def preview_modes(self):
        """
        A list of (internal_name, display_name) tuples for the modes in which
        this page can be displayed for preview/moderation purposes. Ordinarily a page
        will only have one display mode, but subclasses of Page can override this -
        for example, a page containing a form might have a default view of the form,
        and a post-submission 'thankyou' page
        """
        return self.DEFAULT_PREVIEW_MODES

    @property
    def default_preview_mode(self):
        return self.preview_modes[0][0]
Exemplo n.º 3
0
    password_required_template = 'tests/event_page_password_required.html'
    base_form_class = EventPageForm


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", heading="Speaker lineup"),
    InlinePanel('related_links', label="Related links"),
    FieldPanel('categories'),
    # InlinePanel related model uses `pk` not `id`
    InlinePanel('head_counts', label='Head Counts'),
]

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


class HeadCountRelatedModelUsingPK(models.Model):
Exemplo n.º 4
0
class Project(BasePage, ClusterableModel):
    """Page type for a CDH sponsored project or working group."""

    short_description = models.CharField(
        max_length=255,
        blank=True,
        help_text="Brief tagline for display on project card in browse view",
    )
    highlight = models.BooleanField(
        default=False,
        help_text="Include in randomized project display on the home page.",
    )
    cdh_built = models.BooleanField(
        "CDH Built",
        default=False,
        help_text="Project built by CDH Development & Design team.",
    )
    working_group = models.BooleanField(
        "Working Group",
        default=False,
        help_text=
        "Project is a long-term collaborative group associated with the CDH.",
    )
    image = models.ForeignKey(
        "wagtailimages.image",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        help_text="Image for display on project detail page (optional)",
    )
    thumbnail = models.ForeignKey(
        "wagtailimages.image",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        help_text="Image for display on project card (optional)",
    )
    members = models.ManyToManyField(Person, through="Membership")
    tags = ClusterTaggableManager(through=ProjectTag, blank=True)
    # TODO attachments (#245)

    # can only be created underneath project landing page
    parent_page_types = ["projects.ProjectsLandingPage"]
    # no allowed subpages
    subpage_types = []

    # admin edit configuration
    content_panels = Page.content_panels + [
        FieldRowPanel(
            (
                FieldPanel("highlight"),
                FieldPanel("cdh_built"),
                FieldPanel("working_group"),
            ),
            "Settings",
        ),
        FieldRowPanel(
            (ImageChooserPanel("thumbnail"), ImageChooserPanel("image")),
            "Images"),
        FieldPanel("short_description"),
        StreamFieldPanel("body"),
        InlinePanel("related_links", label="Links"),
        InlinePanel(
            "grants",
            panels=[
                FieldRowPanel(
                    (FieldPanel("start_date"), FieldPanel("end_date"))),
                FieldPanel("grant_type"),
            ],
            label="Grants",
        ),
        InlinePanel(
            "memberships",
            panels=[
                FieldRowPanel(
                    (FieldPanel("start_date"), FieldPanel("end_date"))),
                FieldPanel("person"),
                FieldPanel("role"),
            ],
            label="Members",
        ),
        StreamFieldPanel("attachments"),
    ]
    promote_panels = Page.promote_panels + [FieldPanel("tags")]

    # custom manager/queryset logic
    objects = ProjectManager()

    # search fields
    search_fields = BasePage.search_fields + [
        index.SearchField("short_description"),
        index.RelatedFields(
            "members",
            [
                index.SearchField("first_name"),
                index.SearchField("last_name"),
            ],
        ),
    ]

    def __str__(self):
        return self.title

    @property
    def website_url(self):
        """URL for this Project's website, if set"""
        website = self.related_links.filter(type__name="Website").first()
        if website:
            return website.url

    def latest_grant(self):
        """Most recent :class:`Grant` for this Project"""
        if self.grants.count():
            return self.grants.order_by("-start_date").first()

    def current_memberships(self):
        """:class:`MembershipQueryset` of current members sorted by role"""
        # NOTE memberships is a FakeQuerySet from modelcluster.ParentalKey when
        # the page is being previewed in wagtail, so Q lookups are not possible.
        # see: https://github.com/wagtail/django-modelcluster/issues/121
        memberships = Membership.objects.filter(project__pk=self.pk)
        # uses memberships rather than members so that we can retain role
        # information attached to the membership
        today = timezone.now().date()
        # if the last grant for this project is over, display the team
        # for that grant period
        latest_grant = self.latest_grant()
        if latest_grant and latest_grant.end_date and latest_grant.end_date < today:
            return memberships.filter(
                start_date__lte=latest_grant.end_date).filter(
                    models.Q(end_date__gte=latest_grant.start_date)
                    | models.Q(end_date__isnull=True))

        # otherwise, return current members based on date
        return memberships.filter(start_date__lte=today).filter(
            models.Q(end_date__gte=today) | models.Q(end_date__isnull=True))

    def alums(self):
        """:class:`PersonQueryset` of past members sorted by last name"""
        # uses people rather than memberships so that we can use distinct()
        # to ensure people aren't counted multiple times for each grant
        # and because we don't care about role (always 'alum')
        return (self.members.distinct().exclude(
            membership__in=self.current_memberships()).order_by("last_name"))

    def get_sitemap_urls(self, request):
        """Override sitemap to prioritize projects built by CDH with a website."""
        # output is a list of dict; there should only ever be one element. see:
        # https://docs.wagtail.io/en/stable/reference/contrib/sitemaps.html#urls
        urls = super().get_sitemap_urls(request=request)
        if self.website_url and self.cdh_built:
            urls[0]["priority"] = 0.7
        elif self.website_url or self.cdh_built:
            urls[0]["priority"] = 0.6
        return urls
Exemplo n.º 5
0
class YekoGarageBlogPage(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(
        BlogStreamBlock(), verbose_name="Page body", blank=True
    )
    subtitle = models.CharField(blank=True, max_length=255)
    tags = ClusterTaggableManager(through=YekoGarageBlogPageTag, blank=True)
    date_published = models.DateField(
        "Date article published", blank=True, null=True
        )
    search_keywords = ClusterTaggableManager(through='YekoGarageBlogPageKeyword', blank=True, verbose_name='Keywords', related_name='yeko_garage_blog_page_search_keywords',
                                             help_text='Meta Keywords, son palabras clave que se usan para los buscadores')


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

    promote_panels = Page.promote_panels + [
        ImageChooserPanel('image'),
        FieldPanel('search_keywords'),
    ]

    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.yeko_garage_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 = ['YekoGarageBlogIndexPage']

    # Specifies what content types can exist as children of BlogPage.
    # Empty list means that no child content types are allowed.
    subpage_types = []
Exemplo n.º 6
0
class Homepage(MetadataPageMixin, Page):
    hero_headline = models.CharField(
        max_length=140,
        help_text='Hero story headline',
        blank=True,
    )

    hero_story_description = RichTextField(
        features=[
            'bold', 'italic', 'link',
        ]
    )

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

    hero_button_text = models.CharField(
        max_length=50,
        blank=True
    )

    hero_button_url = models.URLField(
        blank=True
    )

    content_panels = Page.content_panels + [
        MultiFieldPanel([
            FieldPanel('hero_headline'),
            FieldPanel('hero_story_description'),
            FieldRowPanel([
                FieldPanel('hero_button_text'),
                FieldPanel('hero_button_url'),
            ]),
            ImageChooserPanel('hero_image'),
        ],
            heading='hero',
            classname='collapsible'
        ),
        InlinePanel('featured_highlights', label='Highlights', max_num=5),
        InlinePanel('featured_news', label='News', max_num=4),
    ]

    subpage_types = [
        'PrimaryPage',
        'PeoplePage',
        'InitiativesPage',
        'Styleguide',
        'NewsPage',
        'ParticipatePage',
        'ParticipatePage2',
        'MiniSiteNameSpace',
        'RedirectingPage',
        'OpportunityPage',
    ]

    def get_context(self, request):
        # We need to expose MEDIA_URL so that the s3 images will show up properly
        # due to our custom image upload approach pre-wagtail
        context = super(Homepage, self).get_context(request)
        print(settings.MEDIA_URL)
        context['MEDIA_URL'] = settings.MEDIA_URL
        return context
Exemplo n.º 7
0
            secondary_topics=BlogPageSecondaryTopic.objects.all().values_list(
                'topic__pk', 'topic__title').distinct(),
            query_string=query_string,
            blog_feed_title=feed_settings.blog_feed_title)
        return context

    def serve_preview(self, request, mode_name):
        """ This is another hack to overcome the MRO issue we were seeing """
        return BibliographyMixin.serve_preview(self, request, mode_name)

    class Meta:
        verbose_name = "Blog, News, Statement Page"


BlogPage.content_panels = Page.content_panels + [
    InlinePanel('authors', label="Authors"),
    SnippetChooserPanel('author_group'),
    FieldPanel('date_published'),
    FieldPanel('introduction'),
    StreamFieldPanel('body'),
    InlinePanel('primary_topics', label="Primary Topics"),
    InlinePanel('secondary_topics', label="Secondary Topics"),
]

BlogPage.promote_panels = Page.promote_panels + PromoteMixin.panels


class BlogIndexPage(Page):
    """
    This page automatically redirects to the latest :model:`blog.BlogPage`.
Exemplo n.º 8
0
class BlogPage(TranslatablePage):
    """
    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)
    categories = ParentalManyToManyField(BlogCategory, blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    date_published = models.DateField("Date article published",
                                      blank=True,
                                      null=True)
    updated = models.DateTimeField(auto_now=True, auto_now_add=False)
    created = models.DateTimeField(auto_now_add=True,
                                   help_text="(automatic) created date")
    content_panels = Page.content_panels + [
        FieldPanel("categories", widget=forms.CheckboxSelectMultiple),
        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

    @property
    def comments(self):
        """
        Similar to the authors function above we're returning all the comments that
        are related to the blog post into a list we can access on the template.
        """
        return Comment.objects.filter_by_instance(
            object_id=self.id, content_type=TranslatablePage)

    @property
    def get_image(self):
        """
        Similar to the authors function above we're returning the image
        related to the blog post into a list we can access on the template.
        """
        return self.image.file.url

    @property
    def comment_count(self):
        return self.comments.count()

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

    # Specifies what content types can exist as children of BlogPage.
    # Empty list means that no child content types are allowed.
    subpage_types = ["BlogPage"]
    api_fields = [APIField("image", serializer=ImageSerializer())]
Exemplo n.º 9
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"),
]
Exemplo n.º 10
0
class OutstationRoutePage(MetadataPageMixin, PageLDMixin, Page):
    template = "route/outstation_route_page.html"

    #banner_title=models.CharField(max_length=100, null=False)
    banner_title = RichTextField(features=['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])
    banner_image = models.ForeignKey("wagtailimages.Image",
                                     null=True,
                                     blank=False,
                                     on_delete=models.SET_NULL,
                                     related_name="+")

    origin = models.ForeignKey("outstationcore.Place",
                               null=True,
                               on_delete=models.SET_NULL,
                               related_name="route_origin")

    destination = models.ForeignKey("outstationcore.Place",
                                    null=True,
                                    on_delete=models.SET_NULL,
                                    related_name="route_destination")

    road_condition_rating = models.PositiveSmallIntegerField()
    #road_map = models.TextField(null=False, help_text="Add road map details")
    #best_time_to_visit = models.TextField(null=False, help_text="Add road map details")
    #alternate_routes = models.TextField(null=False, help_text="Add alternate route details")
    #road_condition = models.TextField(null=False, help_text="Add road condition details")
    highway = models.CharField(max_length=100, null=False)
    total_distance = models.PositiveSmallIntegerField(
        verbose_name=('Total distance (km)'))
    likes = models.ManyToManyField(User, related_name='likes', blank=True)

    canonical_url = models.URLField(null=True,
                                    blank=False,
                                    help_text="Canonical url for this page")
    robots_tag = models.CharField(max_length=100, null=True)

    api_fields = [
        APIField("banner_title"),
        APIField("banner_image"),
        APIField("origin", serializer=PlaceSerializer()),
        APIField("destination", serializer=PlaceSerializer()),
        APIField("on_route_places", serializer=PlaceListSerializer()),
        APIField("destination_places", serializer=PlaceListSerializer()),
        APIField("road_condition_rating"),
        APIField("highway"),
        #APIField("road_map"),
        #APIField("best_time_to_visit"),
        #APIField("alternate_routes"),
        #APIField("road_condition"),
        APIField("total_distance"),
    ]

    content_panels = Page.content_panels + [
        FieldPanel("banner_title"),
        ImageChooserPanel("banner_image"),
        SnippetChooserPanel('origin'),
        SnippetChooserPanel('destination'),
        FieldPanel("highway"),
        MultiFieldPanel([
            InlinePanel("on_route_places"),
        ],
                        heading="On Route Places"),
        MultiFieldPanel([
            InlinePanel("destination_places"),
        ],
                        heading="Destination Tourist Places"),
        MultiFieldPanel([
            InlinePanel("route_information"),
        ],
                        heading="Route Information"),
        FieldPanel("road_condition_rating"),
        #FieldPanel("road_map"),
        #FieldPanel("best_time_to_visit"),
        #FieldPanel("alternate_routes"),
        #FieldPanel("road_condition"),
        FieldPanel("total_distance"),
    ]

    promote_panels = MetadataPageMixin.promote_panels + [
        FieldPanel("canonical_url"),
        FieldPanel("robots_tag")
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)

        location_tags = LocationTag.objects.all()
        context["location_tags"] = location_tags

        trip_types = TripType.objects.all()
        context["trip_types"] = trip_types

        fare_table = FareTable.objects.all()
        context["fare_table"] = fare_table

        context["total_likes"] = self.total_likes()

        context["total_reviews"] = self.total_reviews()

        context["reviews_list"] = self.reviews_list()

        popular_routes = PopularRoutes.objects.all()
        context["popular_routes"] = popular_routes

        context["amenities"] = enums.AmenitiesChoice

        context["vehicle_types"] = enums.VehicleTypeChoice

        return context

    def total_likes(self):
        #print(self.banner_image.file.name)
        return self.likes.count()

    def total_reviews(self):
        return self.page_review.count()

    def reviews_list(self):
        reviews = self.page_review.all().order_by('-publish_date')
        return reviews

    def aggregate_rating(self):
        avg_rating = self.page_review.aggregate(Avg('rating'))["rating__avg"]
        return avg_rating

    #def __unicode__(self):
    #   return self.title

    def get_absolute_url(self):
        """
            Returns absolute url for banner_image to generate image site map
        """
        kwargs = {'slug': self.slug}
        return reverse('outstationroute.detail', kwargs=kwargs)

    def banner_image_url(self):
        """
            Returns the banner_image url for XML images sitemap.
        """
        url = settings.MEDIA_URL + self.banner_image.file.name
        return url if self.banner_image else ''

    def banner_image_title(self):
        """
            Returns the banner_image title for XML images sitemap.
        """
        return self.banner_image.title if self.banner_image else ''

    def ld_entity(self):
        """
            Generates structured data to be displayed as rich snippets on google search
        """
        return extend(
            super().ld_entity(), {
                "@context": "http://schema.org/",
                "@type": "TaxiService",
                "provider": {
                    "@type": "Organization",
                    "name": "Meru",
                    "url": "https://www.meru.in/"
                },
                "aggregateRating": {
                    "ratingValue": self.aggregate_rating(),
                    "reviewCount": self.total_reviews()
                }
            })
Exemplo n.º 11
0
class HomePage(Page):
    """Home Page Model"""
    templates = "templates/home/home_page.html"  # if not specified template loads from templates/app_name/page_class

    # Banner Content Fields
    banner_title = models.CharField(max_length=100, blank=False, null=True)
    banner_subtitle = RichTextField(features=["bold", "italic"])
    banner_image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,   # might cause migration problem, if previously not specified
        blank=False,
        on_delete=models.SET_NULL,
        related_name="+"  # use same as field name
    )

    # Call to action, create another wagtail page
    banner_cta = models.ForeignKey(
        "wagtailcore.Page",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+"
    )

    content = StreamField(
        [
            ("title_and_text", blocks.TitleAndTextBlock()),
            ("full_rich_text", blocks.RichTextBlock()),
            ("simple_richtext", blocks.SimpleRichTextBlock()),
            ("cards", blocks.CardBlock()),
            ("call_to_action", blocks.CTABlock()),
        ],
        null=True,
        blank=True
    )

    # Created fields must be registered here
    content_panels = Page.content_panels + [
        # Banner
        MultiFieldPanel([
            FieldPanel("banner_title"),
            FieldPanel("banner_subtitle"),
            ImageChooserPanel("banner_image"),
            PageChooserPanel("banner_cta"),
        ], heading="Banner Options"),

        # content
        StreamFieldPanel("content"),

        # Image Carousel
        MultiFieldPanel([
            # Why not stream field?
            # Because stream fields can be unlimited, we want to limit the no of fields
            InlinePanel("carousel_images", max_num=5, min_num=1, label="Image")
        ], heading="Carousel Images")
    ]

    # only one home page per site
    max_count = 1

    class Meta:
        verbose_name = "Home Page"
        verbose_name_plural = "Home Pages"
Exemplo n.º 12
0
class HomePage(RoutablePageMixin, Page):
    """Home page model."""

    template = "home/home_page.html"
    subpage_types = [
        'blog.BlogListingPage',
        'contact.ContactPage',
        'flex.FlexPage',
    ]
    parent_page_type = ['wagtailcore.Page']

    banner_title = models.CharField(max_length=100, blank=False, null=True)
    banner_subtitle = RichTextField(features=["bold", "italic"])
    banner_image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=False,
        on_delete=models.SET_NULL,
        related_name="+",
    )
    banner_cta = models.ForeignKey(
        "wagtailcore.Page",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
    )

    content = StreamField([
        ("cta", blocks.CTABlock()),
    ],
                          null=True,
                          blank=True)

    api_fields = [
        APIField("banner_title"),
        APIField("banner_subtitle"),
        APIField("banner_image"),
        APIField("banner_cta"),
        APIField("carousel_images"),
        APIField("content"),
    ]

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                InlinePanel(
                    "carousel_images", max_num=5, min_num=1, label="Image")
            ],
            heading="Carousel Images",
        ),
        StreamFieldPanel("content"),
    ]

    # This is how you'd normally hide promote and settings tabs
    # promote_panels = []
    # settings_panels = []

    banner_panels = [
        MultiFieldPanel(
            [
                FieldPanel("banner_title"),
                FieldPanel("banner_subtitle"),
                ImageChooserPanel("banner_image"),
                PageChooserPanel("banner_cta"),
            ],
            heading="Banner Options",
        ),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(banner_panels, heading="Banner Settings"),
        ObjectList(Page.promote_panels, heading='Promotional Stuff'),
        ObjectList(Page.settings_panels, heading='Settings Stuff'),
    ])

    class Meta:

        verbose_name = "Home Page"
        verbose_name_plural = "Home Pages"

    @route(r'^subscribe/$')
    def the_subscribe_page(self, request, *args, **kwargs):
        context = self.get_context(request, *args, **kwargs)
        return render(request, "home/subscribe.html", context)
Exemplo n.º 13
0
class Extensions(index.Indexed, ClusterableModel):

    # Reference Template
    template = "extensions/extensions_page.html"

    # Create Fields //////////////////
    event_collection = models.ForeignKey(

        "events.CategoryEventCollection",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+"
    )



    assignment_command_types = models.ForeignKey(
        "categories.ExtensionCommandType",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+"
    )


    action = RichTextField(features=['bold', 'italic'], blank=True, null=True)
    explanation = RichTextField(features=['bold', 'italic'], blank=True, null=True)


    video_link = models.CharField(
        max_length=500,
        blank=True,
        null=True,
    )


    # Admin Display Panels
    panels = [

        FieldPanel("event_collection", widget=EventChooser),

        MultiFieldPanel(
            [
                FieldPanel("assignment_command_types", widget=ExtensionChooser, classname="col12 line"),
                FieldPanel("action", classname="col12 line"),
                FieldPanel("explanation", classname="col12")

            ],
            heading="Extension Info",
        ),

        MultiFieldPanel(
            [
                InlinePanel('extension_lexis_link', label='Linked Lexis', classname="col12 line"),
                FieldPanel("video_link", classname="col12"),
            ],
            heading="Extension Links",
        ),

    ]

    # display name
    # return assignment_command and reference its command name property
    def __str__(self):
        return self.assignment_command_types.command_name or ''
        # return ''


    search_fields = [
        index.SearchField('action', partial_match=True),
    ]

    class Meta:
        verbose_name = "Extension"
        verbose_name_plural = "Extensions"
Exemplo n.º 14
0
class Person(BasePage):
    resource_type = "person"
    parent_page_types = ["People"]
    subpage_types = []
    template = "person.html"

    # Content fields
    job_title = CharField(max_length=250)
    role = CharField(max_length=250, choices=ROLE_CHOICES, default="staff")
    description = RichTextField(
        "About",
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional ‘About me’ section content, supports rich text",
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )

    # Card fields
    card_title = CharField("Title", max_length=140, blank=True, default="")
    card_description = TextField("Description",
                                 max_length=400,
                                 blank=True,
                                 default="")
    card_image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
        verbose_name="Image",
    )

    # Meta
    city = CharField(max_length=250, blank=True, default="")
    country = CountryField()
    twitter = CharField(max_length=250, blank=True, default="")
    facebook = CharField(max_length=250, blank=True, default="")
    linkedin = CharField(max_length=250, blank=True, default="")
    github = CharField(max_length=250, blank=True, default="")
    email = CharField(max_length=250, blank=True, default="")
    websites = StreamField(
        StreamBlock([("website", PersonalWebsiteBlock())],
                    max_num=3,
                    required=False),
        null=True,
        blank=True,
        help_text="Optional links to any other personal websites",
    )
    keywords = ClusterTaggableManager(through=PersonTag, blank=True)

    # Content panels
    content_panels = [
        MultiFieldPanel(
            [
                CustomLabelFieldPanel("title", label="Full name"),
                FieldPanel("job_title"),
                FieldPanel("role"),
            ],
            heading="Details",
        ),
        FieldPanel("description"),
        MultiFieldPanel(
            [ImageChooserPanel("image")],
            heading="Image",
            help_text=
            ("Optional header image. If not specified a fallback will be used. "
             "This image is also shown when sharing this page via social media"
             ),
        ),
    ]

    # Card panels
    card_panels = [
        FieldPanel("card_title"),
        FieldPanel("card_description"),
        ImageChooserPanel("card_image"),
    ]

    # Meta panels
    meta_panels = [
        MultiFieldPanel(
            [FieldPanel("city"), FieldPanel("country")],
            heading="Location",
            help_text=("Location fields. The country field is also filterable "
                       "via the people directory page."),
        ),
        MultiFieldPanel([InlinePanel("topics")],
                        heading="Topics this person specializes in"),
        MultiFieldPanel(
            [
                FieldPanel("twitter"),
                FieldPanel("facebook"),
                FieldPanel("linkedin"),
                FieldPanel("github"),
                FieldPanel("email"),
            ],
            heading="Profiles",
            help_text="",
        ),
        StreamFieldPanel("websites"),
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("social_image"),
                FieldPanel("keywords"),
            ],
            heading="SEO",
            help_text=(
                "Optional fields to override the default title and description "
                "for SEO purposes"),
        ),
    ]

    # Settings panels
    settings_panels = [FieldPanel("slug")]

    # Tabs
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading="Content"),
        ObjectList(card_panels, heading="Card"),
        ObjectList(meta_panels, heading="Meta"),
        ObjectList(settings_panels, heading="Settings", classname="settings"),
    ])

    @property
    def events(self):
        """
        Return upcoming events where this person is a speaker,
        ordered by start date
        """
        from ..events.models import Event

        upcoming_events = Event.published_objects.filter(
            start_date__gte=datetime.datetime.now())

        speaker_events = Event.published_objects.none()

        for event in upcoming_events.all():
            # add the event to the list if the current person is a speaker
            if event.has_speaker(self):
                speaker_events = speaker_events | Event.published_objects.page(
                    event)

        return speaker_events.order_by("start_date")

    @property
    def articles(self):
        """
        Return articles and external articles where this person is (one of) the authors,
        ordered by article date, most recent first
        """
        from ..articles.models import Article
        from ..externalcontent.models import ExternalArticle

        articles = Article.published_objects.none()
        external_articles = ExternalArticle.published_objects.none()

        all_articles = Article.published_objects.all()
        all_external_articles = ExternalArticle.published_objects.all()

        for article in all_articles:
            if article.has_author(self):
                articles = articles | Article.published_objects.page(article)

        for external_article in all_external_articles:
            if external_article.has_author(self):
                external_articles = external_articles | (
                    ExternalArticle.published_objects.page(external_article))

        return sorted(chain(articles, external_articles),
                      key=attrgetter("date"),
                      reverse=True)

    @property
    def videos(self):
        """
        Return the most recent videos and external videos where this person is (one of)
        the speakers.
        """
        from ..videos.models import Video
        from ..externalcontent.models import ExternalVideo

        videos = Video.published_objects.none()
        external_videos = ExternalVideo.published_objects.none()

        all_videos = Video.published_objects.all()
        all_external_videos = ExternalVideo.published_objects.all()

        for video in all_videos:
            if video.has_speaker(self):
                videos = videos | Video.published_objects.page(video)

        for external_video in all_external_videos:
            if external_video.has_speaker(self):
                external_videos = external_videos | (
                    ExternalVideo.published_objects.page(external_video))

        return sorted(chain(videos, external_videos),
                      key=attrgetter("date"),
                      reverse=True)

    @property
    def role_group(self):
        return {
            "slug": self.role,
            "title": dict(ROLE_CHOICES).get(self.role, "")
        }

    @property
    def country_group(self):
        return ({
            "slug": self.country.code.lower(),
            "title": self.country.name
        } if self.country else {
            "slug": ""
        })
Exemplo n.º 15
0
class HomePageCarouselItem(Orderable, AbstractCarouselItem):
    page = ParentalKey('HomePage',
                       related_name='carousel_items',
                       on_delete=models.CASCADE)


class HomePageRelatedLink(Orderable, AbstractRelatedLink):
    page = ParentalKey('HomePage',
                       related_name='related_links',
                       on_delete=models.CASCADE)


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

# Standard pages


class StandardPage(Page):
    page_ptr = models.OneToOneField(Page,
                                    parent_link=True,
                                    related_name='+',
                                    on_delete=models.CASCADE)
    intro = RichTextField(blank=True)
    body = RichTextField(blank=True)
    feed_image = models.ForeignKey('wagtailimages.Image',
                                   null=True,
Exemplo n.º 16
0
     [
         FieldPanel('how_does_it_use_data_collected'),
         FieldPanel('data_collection_policy_is_bad'),
     ],
     heading='How does it use this data',
     classname='collapsible',
 ),
 MultiFieldPanel([
     FieldPanel('user_friendly_privacy_policy'),
 ],
                 heading='Privacy policy',
                 classname='collapsible'),
 MultiFieldPanel([
     InlinePanel(
         'privacy_policy_links',
         label='link',
         min_num=1,
         max_num=3,
     ),
 ],
                 heading='Privacy policy links',
                 classname='collapsible'),
 MultiFieldPanel([
     FieldPanel('show_ding_for_minimum_security_standards'),
     FieldPanel('meets_minimum_security_standards'),
     FieldPanel('uses_encryption'),
     FieldPanel('uses_encryption_helptext'),
     FieldPanel('security_updates'),
     FieldPanel('security_updates_helptext'),
     FieldPanel('strong_password'),
     FieldPanel('strong_password_helptext'),
     FieldPanel('manage_vulnerabilities'),
Exemplo n.º 17
0
class ParticipatePage2(PrimaryPage):
    parent_page_types = ['Homepage']
    template = 'wagtailpages/static/participate_page2.html'

    ctaHero = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='primary_hero_participate',
        verbose_name='Primary Hero Image',
    )

    ctaHeroHeader = models.TextField(
        blank=True,
    )

    ctaHeroSubhead = RichTextField(
        features=[
            'bold', 'italic', 'link',
        ],
        blank=True,
    )

    ctaCommitment = models.TextField(
        blank=True,
    )

    ctaButtonTitle = models.CharField(
        verbose_name='Button Text',
        max_length=250,
        blank=True,
    )

    ctaButtonURL = models.TextField(
        verbose_name='Button URL',
        blank=True,
    )

    ctaHero2 = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='primary_hero_participate2',
        verbose_name='Primary Hero Image',
    )

    ctaHeroHeader2 = models.TextField(
        blank=True,
    )

    ctaHeroSubhead2 = RichTextField(
        features=[
            'bold', 'italic', 'link',
        ],
        blank=True,
    )

    ctaCommitment2 = models.TextField(
        blank=True,
    )

    ctaButtonTitle2 = models.CharField(
        verbose_name='Button Text',
        max_length=250,
        blank=True,
    )

    ctaButtonURL2 = models.TextField(
        verbose_name='Button URL',
        blank=True,
    )

    ctaHero3 = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='primary_hero_participate3',
        verbose_name='Primary Hero Image',
    )

    ctaHeroHeader3 = models.TextField(
        blank=True,
    )

    ctaHeroSubhead3 = RichTextField(
        features=[
            'bold', 'italic', 'link',
        ],
        blank=True,
    )

    ctaCommitment3 = models.TextField(
        blank=True,
    )

    ctaFacebook3 = models.TextField(
        blank=True,
    )

    ctaTwitter3 = models.TextField(
        blank=True,
    )

    ctaEmailShareBody3 = models.TextField(
        blank=True,
    )

    ctaEmailShareSubject3 = models.TextField(
        blank=True,
    )

    h2 = models.TextField(
        blank=True,
    )

    h2Subheader = models.TextField(
        blank=True,
        verbose_name='H2 Subheader',
    )

    content_panels = Page.content_panels + [
        MultiFieldPanel([
            ImageChooserPanel('ctaHero'),
            FieldPanel('ctaHeroHeader'),
            FieldPanel('ctaHeroSubhead'),
            FieldPanel('ctaCommitment'),
            FieldPanel('ctaButtonTitle'),
            FieldPanel('ctaButtonURL'),
        ], heading="Primary CTA"),
        FieldPanel('h2'),
        FieldPanel('h2Subheader'),
        InlinePanel('featured_highlights', label='Highlights Group 1', max_num=3),
        MultiFieldPanel([
            ImageChooserPanel('ctaHero2'),
            FieldPanel('ctaHeroHeader2'),
            FieldPanel('ctaHeroSubhead2'),
            FieldPanel('ctaCommitment2'),
            FieldPanel('ctaButtonTitle2'),
            FieldPanel('ctaButtonURL2'),
        ], heading="CTA 2"),
        InlinePanel('featured_highlights2', label='Highlights Group 2', max_num=6),
        MultiFieldPanel([
            ImageChooserPanel('ctaHero3'),
            FieldPanel('ctaHeroHeader3'),
            FieldPanel('ctaHeroSubhead3'),
            FieldPanel('ctaCommitment3'),
            FieldPanel('ctaFacebook3'),
            FieldPanel('ctaTwitter3'),
            FieldPanel('ctaEmailShareSubject3'),
            FieldPanel('ctaEmailShareBody3'),
        ], heading="CTA 3"),
        InlinePanel('cta4', label='CTA Group 4', max_num=3),
    ]
Exemplo n.º 18
0
class Application(ClusterableModel):
    """An application is made to strive to acquire an position"""

    position = models.ForeignKey(
        'Position',
        related_name='applications',
        on_delete=models.PROTECT,
        blank=False,
    )

    applicant = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        blank=False,
    )

    class Meta:
        verbose_name = _('Application')
        verbose_name_plural = _('Applications')
        unique_together = ('position', 'applicant')
        default_permissions = ()

    STATUS_CHOICES = (
        ('draft', _('Draft')),
        ('submitted', _('Submitted')),
        ('approved', _('Approved')),
        ('disapproved', _('Disapproved')),
        ('appointed', _('Appointed')),
        ('turned_down', _('Turned down')),
    )

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        verbose_name=_('Status'),
        blank=False,
        null=False,
    )

    # ---- Application Information ------
    cover_letter = models.TextField(
        verbose_name=_('Cover Letter'),
        help_text=_('Present yourself and state why you are who we are '
                    'looking for'),
        blank=True,
    )
    qualifications = models.TextField(
        verbose_name=_('Qualifications'),
        help_text=_('Give a summary of relevant qualifications'),
        blank=True,
    )

    # Access overhead
    removed = models.BooleanField(default=False, )

    def __str__(self) -> str:
        return '%(applicant)s - %(position)s' % {
            'position': self.position,
            'applicant': self.applicant
        }

    rejection_date = models.DateField(verbose_name=_('Rejection date'),
                                      null=True,
                                      blank=True)

    # ------ Administrator settings ------
    panels = [
        MultiFieldPanel([
            FieldRowPanel([
                FieldPanel('applicant'),
                FieldPanel('position'),
            ]),
            FieldPanel('cover_letter'),
            FieldPanel('qualifications'),
            InlinePanel('references'),
            FieldPanel('status'),
        ])
    ]
Exemplo n.º 19
0
class HomePage(ContentPage):

    # Only available at root level
    parent_page_types = ['wagtailcore.Page']

    content_panels = [
        InlinePanel('hero_image_layers',
                    label="Hero Image Layers",
                    help_text="Bottom-most layer goes first.")
    ] + ContentPage.content_panels

    # There can only be one HomePage
    @classmethod
    def can_create_at(cls, parent):
        return super(HomePage,
                     cls).can_create_at(parent) and not cls.objects.exists()

    def get_context(self, request):
        context = super(HomePage, self).get_context(request)

        context['links'] = [{
            "name": "Patreon",
            "icon": "fab fa-patreon",
            "link": "https://www.patreon.com/GemExchange"
        }, {
            "name":
            "Toyhouse",
            "icon":
            "fa fa-home",
            "link":
            "http://toyhou.se/~world/1420.gemexchange-jo-arca"
        }, {
            "name":
            "FurAffinity",
            "icon":
            "fa fa-paw",
            "link":
            "https://www.furaffinity.net/user/gemexchange"
        }, {
            "name": "Twitter",
            "icon": "fab fa-twitter",
            "link": "https://twitter.com/Gem_Exchange"
        }, {
            "name":
            "Github",
            "icon":
            "fab fa-github",
            "link":
            "https://github.com/juan0tron/the-gem-exchange"
        }, {
            "name": "DeviantArt",
            "icon": "fab fa-deviantart",
            "link": "https://gemexchange.deviantart.com/"
        }, {
            "name": "Discord",
            "icon": "fab fa-discord",
            "link": "https://discord.gg/T9Xrjs5"
        }]

        context['compendium_backgrounds'] = SubSpecies.objects.filter(
            name="Standard").exclude(background__isnull=True)[:3]

        return context
Exemplo n.º 20
0
class Experiment(ClusterableModel):
    STATUS_CHOICES = [
        ('draft', "Draft"),
        ('live', "Live"),
        ('completed', "Completed"),
    ]
    name = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    control_page = models.ForeignKey('wagtailcore.Page',
                                     related_name='+',
                                     on_delete=models.CASCADE)
    goal = models.ForeignKey('wagtailcore.Page',
                             related_name='+',
                             on_delete=models.SET_NULL,
                             null=True,
                             blank=True)
    status = models.CharField(max_length=10,
                              choices=STATUS_CHOICES,
                              default='draft')
    winning_variation = models.ForeignKey('wagtailcore.Page',
                                          related_name='+',
                                          on_delete=models.SET_NULL,
                                          null=True)

    panels = [
        FieldPanel('name'),
        FieldPanel('slug'),
        PageChooserPanel('control_page'),
        InlinePanel('alternatives', label="Alternatives"),
        PageChooserPanel('goal'),
        FieldPanel('status'),
    ]

    def __init__(self, *args, **kwargs):
        super(Experiment, self).__init__(*args, **kwargs)
        self._initial_status = self.status

    def activate_alternative_draft_content(self):
        # For any alternative pages that are unpublished, copy the latest draft revision
        # to the main table (with is_live=False) so that the revision shown as an alternative
        # is not an out-of-date one
        for alternative in self.alternatives.select_related('page'):
            if not alternative.page.live:
                revision = alternative.page.get_latest_revision_as_page()
                revision.live = False
                revision.has_unpublished_changes = True
                revision.save()

    def get_variations(self):
        return [self.control_page] + [
            alt.page for alt in self.alternatives.select_related('page')
        ]

    def get_variation_for_user(self, user_id):
        variations = self.get_variations()

        # choose uniformly from variations, based on a hash of user_id and experiment.slug
        hash_input = "{0}.{1}".format(self.slug, user_id)
        hash_str = sha1(hash_input.encode('utf-8')).hexdigest()[:7]
        variation_index = int(hash_str, 16) % len(variations)
        return variations[variation_index]

    def start_experiment_for_user(self, user_id, request):
        """
        Record a new participant and return the variation for them to use
        """
        variation = self.get_variation_for_user(user_id)
        get_backend().record_participant(self, user_id, variation, request)
        return variation

    def record_completion_for_user(self, user_id, request):
        backend = get_backend()
        variation = self.get_variation_for_user(user_id)
        backend.record_completion(self, user_id, variation, request)

    def select_winner(self, variation):
        self.winning_variation = variation
        self.status = 'completed'
        self.save()

    def __str__(self):
        return self.name
Exemplo n.º 21
0
class LandingPage(Page):
    template = 'home/index.jinja'
    FEATURED_CONTENT_COUNT = 6
    MAX_CALLOUT_ENTRIES = 3
    RECENT_FORUM_ACTIVITY_COUNT = 5

    mission_statement = models.CharField(max_length=512)
    community_statement = models.TextField()

    def get_featured_content(self):
        return self.featured_content_queue.select_related(
            'image', 'codebase_image', 'link_codebase',
            'link_page').all()[:self.FEATURED_CONTENT_COUNT]

    def get_canned_forum_activity(self):
        random_submitters = User.objects.select_related(
            'member_profile').filter(pk__in=(3, 5, 7, 11, 13, 17))
        return [{
            'title':
            "Generated Forum Topic {}".format(i),
            'submitter_name':
            random_submitters[i].member_profile.name,
            'submitter_url':
            random_submitters[i].member_profile.get_absolute_url(),
            'date_created':
            datetime.now(),
            'url':
            "https://forum.example.com/topic/{}".format(i),
        } for i in range(self.RECENT_FORUM_ACTIVITY_COUNT)]

    def _discourse_username_to_submitter(self, username, topic, topic_title):
        submitter = None
        submitter_url = None
        if username != 'comses':
            try:
                submitter = User.objects.get(username=username)
            except User.DoesNotExist:
                pass
        if submitter is None:
            category_id = topic['category_id']
            logger.debug("category id: %s, topic title: %s, topic: %s",
                         category_id, topic_title, topic)
            # special case lookup for real submitter
            # FIXME: get rid of magic constants
            target_object = None
            if category_id == 6:
                # jobs and appointments
                target_object = Job.objects.filter(
                    title=topic_title).order_by('-date_created').first()
            elif category_id == 7:
                # events
                target_object = Event.objects.filter(
                    title=topic_title).order_by('-date_created').first()
            elif category_id == 8:
                target_object = Codebase.objects.filter(
                    title=topic_title).order_by('-date_created').first()
            if target_object:
                submitter = target_object.submitter
                submitter_url = submitter.member_profile.get_absolute_url()
            else:
                submitter = User.get_anonymous()
        return submitter, submitter_url

    def get_recent_forum_activity(self):
        # FIXME: refactor and clean up logic to form a more sensible discourse api
        # Discourse API endpoint documented at http://docs.discourse.org/#tag/Topics%2Fpaths%2F~1latest.json%2Fget
        if settings.DEPLOY_ENVIRONMENT.is_development():
            return self.get_canned_forum_activity()
        recent_forum_activity = cache.get('recent_forum_activity')
        if recent_forum_activity:
            return recent_forum_activity
        # transform topics list of dictionaries into web template format with title, submitter, date_created, and url.
        try:
            r = requests.get(build_discourse_url('latest.json'),
                             params={
                                 'order': 'created',
                                 'sort': 'asc'
                             },
                             timeout=3.0)
            posts_dict = r.json()
            topics = posts_dict['topic_list']['topics']
            recent_forum_activity = []
            for topic in topics[:self.RECENT_FORUM_ACTIVITY_COUNT]:
                topic_title = topic['title']
                topic_url = build_discourse_url('t/{0}/{1}'.format(
                    topic['slug'], topic['id']))
                # getting back to the original submitter involves some trickery.
                # The Discourse embed Javascript queues up a crawler to hit the given page and parses it for content to use
                # as the initial topic text. However, this topic gets added as a specific Discourse User (`comses`,
                # see https://meta.discourse.org/t/embedding-discourse-comments-via-javascript/31963/150 for more details)
                # and so we won't always have the direct username of the submitter without looking it up by
                # 1. Discourse category_id (6 = jobs & appointments, 7 = events, 8 = codebase)
                # 2. Title (not guaranteed to be unique)

                last_poster_username = topic['last_poster_username']
                submitter, submitter_url = self._discourse_username_to_submitter(
                    last_poster_username, topic, topic_title)

                recent_forum_activity.append({
                    'title':
                    topic_title,
                    'submitter_name':
                    submitter.username,
                    'submitter_url':
                    submitter_url,
                    # FIXME: handle created_at=None gracefully, via default date?
                    'date_created':
                    datetime.strptime(topic.get('created_at'),
                                      "%Y-%m-%dT%H:%M:%S.%fZ"),
                    'url':
                    topic_url,
                })
            cache.set('recent_forum_activity', recent_forum_activity, 3600)
            return recent_forum_activity
        except Exception as e:
            logger.exception(e)
            return []

    def get_latest_jobs(self):
        return Job.objects.order_by('-date_created')[:self.MAX_CALLOUT_ENTRIES]

    def get_upcoming_events(self):
        return Event.objects.upcoming().order_by(
            'start_date')[:self.MAX_CALLOUT_ENTRIES]

    def get_context(self, request, *args, **kwargs):
        context = super(LandingPage, self).get_context(request, *args,
                                                       **kwargs)
        context['featured_content'] = self.get_featured_content()
        context['recent_forum_activity'] = self.get_recent_forum_activity()
        context['latest_jobs'] = self.get_latest_jobs()
        context['upcoming_events'] = self.get_upcoming_events()
        return context

    content_panels = Page.content_panels + [
        FieldPanel('mission_statement', widget=forms.Textarea),
        FieldPanel('community_statement'),
        InlinePanel('featured_content_queue', label=_('Featured Content')),
    ]
Exemplo n.º 22
0
class ServicePage(JanisBasePage):
    janis_url_page_type = "services"

    steps = StreamField(
        [
            ('basic_step',
             RichTextBlock(features=WYSIWYG_SERVICE_STEP, label='Basic Step')),
            (
                'step_with_options_accordian',
                StructBlock(
                    [
                        (
                            'options_description',
                            RichTextBlock(
                                features=WYSIWYG_SERVICE_STEP,
                                # richTextPlaceholder.js searches for the class 'coa-option-description' and replaces placeholder text
                                # The placeholder text is not part of the richtext input, but rather a div mask.
                                classname='coa-option-description',
                            )),
                        ('options',
                         ListBlock(
                             StructBlock([
                                 ('option_name',
                                  TextBlock(
                                      label=
                                      'Option name. (When clicked, this name will expand the content for this option'
                                  )),
                                 ('option_description',
                                  RichTextBlock(
                                      features=WYSIWYG_SERVICE_STEP,
                                      label='Option Content',
                                  )),
                             ]), )),
                    ],
                    label="Step With Options")),
            (
                'step_with_locations',
                StructBlock(
                    [
                        (
                            'locations_description',
                            RichTextBlock(
                                features=WYSIWYG_SERVICE_STEP,
                                # richTextPlaceholder.js searches for the class 'coa-option-description' and replaces placeholder text
                                # The placeholder text is not part of the richtext input, but rather a div mask.
                                classname='coa-locations-description',
                            )),
                        ('locations',
                         ListBlock(
                             PageChooserBlock(label="Location",
                                              page_type=[LocationPage]))),
                    ],
                    label="Step with locations")),
        ],
        verbose_name=
        'Write out the steps a resident needs to take to use the service',
        # this gets called in the help panel
        help_text=
        'A step may have a basic text step or an options accordion which reveals two or more options',
        blank=True)

    dynamic_content = StreamField(
        [
            ('map_block',
             SnippetChooserBlockWithAPIGoodness('base.Map', icon='site')),
            ('what_do_i_do_with_block', WhatDoIDoWithBlock()),
            ('collection_schedule_block', CollectionScheduleBlock()),
            ('recollect_block', RecollectBlock()),
        ],
        verbose_name=
        'Add any maps or apps that will help the resident use the service',
        blank=True)
    additional_content = RichTextField(
        features=WYSIWYG_GENERAL,
        verbose_name='Write any additional content describing the service',
        help_text='Section header: What else do I need to know?',
        blank=True)

    base_form_class = ServicePageForm

    short_description = models.TextField(
        max_length=SHORT_DESCRIPTION_LENGTH,
        blank=True,
        verbose_name='Write a description of this service')

    content_panels = [
        FieldPanel('title_en', widget=countMe),
        FieldPanel('title_es', widget=countMe),
        FieldPanel('title_ar'),
        FieldPanel('title_vi'),
        FieldPanel('short_description', widget=countMeTextArea),
        InlinePanel('topics', label='Topics'),
        InlinePanel('related_departments', label='Related Departments'),
        MultiFieldPanel([
            HelpPanel(steps.help_text, classname="coa-helpPanel"),
            StreamFieldPanel('steps')
        ],
                        heading=steps.verbose_name,
                        classname='coa-multiField-nopadding'),
        StreamFieldPanel('dynamic_content'),
        MultiFieldPanel([
            HelpPanel(additional_content.help_text, classname="coa-helpPanel"),
            FieldPanel('additional_content')
        ],
                        heading=additional_content.verbose_name,
                        classname='coa-multiField-nopadding'),
        InlinePanel('contacts', label='Contacts'),
    ]
Exemplo n.º 23
0
class StoryPage(Page):
    MAX_RELATED_STORIES = 10

    # This is a leaf page
    subpage_types = []
    parent_page_types = ['news.StoryIndexPage']

    author = models.ForeignKey('common.User',
                               null=True,
                               blank=True,
                               on_delete=models.SET_NULL,
                               related_name="+")
    date = models.DateField("post date")
    lede = models.CharField(
        max_length=1024,
        help_text="A short intro that appears in the story index page")
    tags = ClusterTaggableManager(through=StoryTag, blank=True)
    categories = ParentalManyToManyField(
        'news.StoryCategory',
        blank=True,
        help_text="The set of categories this page will be served")

    # Add allowed block types to StreamPanel
    content = StreamField([
        ('paragraph',
         RichTextBlock(
             features=['h2', 'h3', 'bold', 'italic', 'link', 'ol', 'ul'])),
        ('markdown', ZOrderMarkdownBlock(icon='code')),
        ('image',
         StructBlock([('image', ImageChooserBlock()),
                      ('caption', CharBlock(required=False))])),
        ('carousel', ImageCarouselBlock()),
        ('quote', BlockQuoteBlock()),
        ('embedded_content', EmbedContentBlock()),
    ])

    def get_context(self, request):

        context = super().get_context(request)
        tags_list = list(self.tags.all())

        # Collects set of stories that has the same tags as this story.
        related = StoryPage.objects.live().order_by('-first_published_at')
        related = related.filter(tags__in=tags_list)
        related = related.exclude(id=self.id)
        if related.count() > 0:
            related = related.distinct()[0:self.MAX_RELATED_STORIES]
            context["related"] = related

        try:
            context['prevstory'] = self.get_previous_by_date(
                tags__in=tags_list)
        except (StoryPage.DoesNotExist, ValueError):
            pass

        try:
            context['nextstory'] = self.get_next_by_date(tags__in=tags_list)
        except (StoryPage.DoesNotExist, ValueError):
            pass

        return context

    def hero_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    def media_thumbnail_url(self):
        for child in self.content:
            if child.block.name == 'embedded_content':
                return child.value.thumbnail_url
        return None

    def hero_image_url(self):
        hero_image = self.hero_image()
        if hero_image:
            return hero_image.url
        return self.media_thumbnail_url()

    def author_name(self):
        if not self.author:
            return ANONYMOUS_AUTHOR_NAME
        else:
            return self.owner.username

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

    content_panels = Page.content_panels + [
        MultiFieldPanel([
            StoryAuthorFieldPanel('author', widget=forms.Select),
            FieldPanel('date'),
            FieldPanel('tags'),
            FieldPanel('categories', widget=forms.CheckboxSelectMultiple),
        ]),
        FieldPanel('lede'),
        InlinePanel('gallery_images', label="Gallery Images"),
        StreamFieldPanel('content')
    ]
Exemplo n.º 24
0
class Article(BasePage):
    # IMPORTANT: EACH ARTICLE is NOW LABELLED "POST" IN THE FRONT END

    resource_type = "article"  # If you change this, CSS will need updating, too
    parent_page_types = ["Articles"]
    subpage_types = []
    template = "article.html"

    class Meta:
        verbose_name = "post"  # NB
        verbose_name_plural = "posts"  # NB

    # Content fields
    description = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional short text description, max. 400 characters",
        max_length=400,
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )
    body = CustomStreamField(help_text=(
        "The main post content. Supports rich text, images, embed via URL, "
        "embed via HTML, and inline code snippets"))
    related_links_mdn = StreamField(
        StreamBlock([("link", ExternalLinkBlock())], required=False),
        blank=True,
        null=True,
        help_text="Optional links to MDN Web Docs for further reading",
        verbose_name="Related MDN links",
    )

    # Card fields
    card_title = CharField("Title", max_length=140, blank=True, default="")
    card_description = TextField("Description",
                                 max_length=400,
                                 blank=True,
                                 default="")
    card_image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
        verbose_name="Image",
    )

    # Meta fields
    date = DateField(
        "Post date",
        default=datetime.date.today,
        help_text="The date the post was published",
    )
    authors = StreamField(
        StreamBlock(
            [
                ("author", PageChooserBlock(target_model="people.Person")),
                ("external_author", ExternalAuthorBlock()),
            ],
            required=False,
        ),
        blank=True,
        null=True,
        help_text=(
            "Optional list of the post's authors. Use ‘External author’ to add "
            "guest authors without creating a profile on the system"),
    )
    keywords = ClusterTaggableManager(through=ArticleTag, blank=True)

    # Content panels
    content_panels = BasePage.content_panels + [
        FieldPanel("description"),
        MultiFieldPanel(
            [ImageChooserPanel("image")],
            heading="Image",
            help_text=
            ("Optional header image. If not specified a fallback will be used. "
             "This image is also shown when sharing this page via social media"
             ),
        ),
        StreamFieldPanel("body"),
        StreamFieldPanel("related_links_mdn"),
    ]

    # Card panels
    card_panels = [
        FieldPanel("card_title"),
        FieldPanel("card_description"),
        ImageChooserPanel("card_image"),
    ]

    # Meta panels
    meta_panels = [
        FieldPanel("date"),
        StreamFieldPanel("authors"),
        MultiFieldPanel(
            [InlinePanel("topics")],
            heading="Topics",
            help_text=
            ("The topic pages this post will appear on. The first topic in the "
             "list will be treated as the primary topic and will be shown in the "
             "page’s related content."),
        ),
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("social_image"),
                FieldPanel("keywords"),
            ],
            heading="SEO",
            help_text=(
                "Optional fields to override the default title and description "
                "for SEO purposes"),
        ),
    ]

    # Settings panels
    settings_panels = [FieldPanel("slug")]

    # Tabs
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading="Content"),
        ObjectList(card_panels, heading="Card"),
        ObjectList(meta_panels, heading="Meta"),
        ObjectList(settings_panels, heading="Settings", classname="settings"),
    ])

    def get_absolute_url(self):
        # For the RSS feed
        return self.full_url

    @property
    def primary_topic(self):
        """Return the first (primary) topic specified for the Article."""
        article_topic = self.topics.first()
        return article_topic.topic if article_topic else None

    @property
    def read_time(self):
        return str(readtime.of_html(str(self.body)))

    @property
    def related_resources(self):
        """Returns resources that are related to the current resource, i.e.
        live, public Articles and Videos which have the same Topics."""
        topic_pks = [topic.topic.pk for topic in self.topics.all()]
        return get_combined_articles_and_videos(
            self, topics__topic__pk__in=topic_pks)

    @property
    def month_group(self):
        return self.date.replace(day=1)

    def has_author(self, person):
        for author in self.authors:  # pylint: disable=not-an-iterable
            if author.block_type == "author" and str(author.value) == str(
                    person.title):
                return True
        return False
Exemplo n.º 25
0
class Movie(Page):
    """Фильм"""
    tagline = models.CharField("Слоган", max_length=100, default='')
    description = RichTextField("Описание", blank=True)
    image = models.ForeignKey('wagtailimages.Image',
                              null=True,
                              blank=True,
                              on_delete=models.SET_NULL,
                              related_name='+')
    year = models.PositiveSmallIntegerField("Дата выхода", default=2019)
    country = models.CharField("Страна", max_length=30)
    directors = ParentalManyToManyField(Actor,
                                        verbose_name="режиссер",
                                        related_name="film_director")
    actors = ParentalManyToManyField(Actor,
                                     verbose_name="актеры",
                                     related_name="film_actor")
    genres = ParentalManyToManyField(Genre, verbose_name="жанры")
    world_premiere = models.DateField("Примьера в мире", default=date.today)
    budget = models.PositiveIntegerField(
        "Бюджет", default=0, help_text="указывать сумму в долларах")
    fees_in_usa = models.PositiveIntegerField(
        "Сборы в США", default=0, help_text="указывать сумму в долларах")
    fees_in_world = models.PositiveIntegerField(
        "Сборы в мире", default=0, help_text="указывать сумму в долларах")
    movie_category = ParentalManyToManyField(Category,
                                             verbose_name="Категория")

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

    content_panels = Page.content_panels + [
        FieldPanel('tagline'),
        ImageChooserPanel('image'),
        FieldPanel('year'),
        FieldPanel('country'),
        FieldPanel('directors'),
        FieldPanel('actors'),
        FieldPanel('world_premiere'),
        FieldPanel('budget'),
        FieldPanel('fees_in_usa'),
        FieldPanel('fees_in_world'),
        InlinePanel('gallery_images', label='Кадры из фильма'),
        InlinePanel('ratings', label='Рейтинг'),
        InlinePanel('reviews', label='Отзывы'),
        FieldPanel('movie_category', widget=forms.CheckboxSelectMultiple),
        FieldPanel('genres', widget=forms.CheckboxSelectMultiple),
    ]

    api_fields = [
        APIField('title'),
        APIField('description'),
        APIField('actors'),
        APIField('genres'),
        APIField('movie_category'),
    ]

    def __str__(self):
        return self.title

    def get_review(self):
        return self.reviews_set.filter(parent__isnull=True)

    class Meta:
        verbose_name = "Фильм"
        verbose_name_plural = "Фильмы"
        db_table = "'catalog'.'movie'"
Exemplo n.º 26
0
class Video(BasePage):
    resource_type = "video"
    parent_page_types = ["Videos"]
    subpage_types = []
    template = "video.html"

    # Content fields
    description = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional short text description, max. 400 characters",
        max_length=400,
    )
    body = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES,
        help_text=(
            "Optional body content. Supports rich text, images, embed via URL, "
            "embed via HTML, and inline code snippets"),
    )
    related_links = StreamField(
        StreamBlock([("link", ExternalLinkBlock())], required=False),
        null=True,
        blank=True,
        help_text="Optional links further reading",
        verbose_name="Related links",
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )
    types = CharField(max_length=14, choices=VIDEO_TYPE, default="conference")
    duration = CharField(
        max_length=30,
        blank=True,
        null=True,
        help_text=
        ("Optional video duration in MM:SS format e.g. “12:34”. Shown when the "
         "video is displayed as a card"),
    )
    transcript = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES,
        help_text="Optional text transcript of the video, supports rich text",
    )
    video_url = StreamField(
        StreamBlock([("embed", EmbedBlock())],
                    min_num=1,
                    max_num=1,
                    required=True),
        help_text=
        ("Embed URL for the video e.g. https://www.youtube.com/watch?v=kmk43_2dtn0"
         ),
    )
    speakers = StreamField(
        StreamBlock(
            [("speaker", PageChooserBlock(target_model="people.Person"))],
            required=False,
        ),
        blank=True,
        null=True,
        help_text=
        "Optional list of people associated with or starring in the video",
    )

    # Card fields
    card_title = CharField("Title", max_length=140, blank=True, default="")
    card_description = TextField("Description",
                                 max_length=400,
                                 blank=True,
                                 default="")
    card_image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
        verbose_name="Image",
    )

    # Meta fields
    date = DateField("Upload date", default=datetime.date.today)
    keywords = ClusterTaggableManager(through=VideoTag, blank=True)

    # Content panels
    content_panels = BasePage.content_panels + [
        FieldPanel("description"),
        ImageChooserPanel("image"),
        StreamFieldPanel("video_url"),
        FieldPanel("body"),
        StreamFieldPanel("related_links"),
        FieldPanel("transcript"),
    ]

    # Card panels
    card_panels = [
        FieldPanel("card_title"),
        FieldPanel("card_description"),
        ImageChooserPanel("card_image"),
    ]

    # Meta panels
    meta_panels = [
        FieldPanel("date"),
        StreamFieldPanel("speakers"),
        MultiFieldPanel(
            [InlinePanel("topics")],
            heading="Topics",
            help_text=
            ("These are the topic pages the video will appear on. The first topic "
             "in the list will be treated as the primary topic and will be shown "
             "in the page’s related content."),
        ),
        FieldPanel("duration"),
        MultiFieldPanel(
            [FieldPanel("types")],
            heading="Type",
            help_text="Choose a video type to help people search for the video",
        ),
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("social_image"),
                FieldPanel("keywords"),
            ],
            heading="SEO",
            help_text=(
                "Optional fields to override the default title and description "
                "for SEO purposes"),
        ),
    ]

    settings_panels = BasePage.settings_panels + [FieldPanel("slug")]

    # Tabs
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading="Content"),
        ObjectList(card_panels, heading="Card"),
        ObjectList(meta_panels, heading="Meta"),
        ObjectList(settings_panels, heading="Settings", classname="settings"),
    ])

    def get_absolute_url(self):
        # For the RSS feed
        return self.full_url

    @property
    def primary_topic(self):
        """Return the first (primary) topic specified for the video."""
        video_topic = self.topics.first()
        return video_topic.topic if video_topic else None

    @property
    def read_time(self):
        return str(readtime.of_html(str(self.body)))

    @property
    def related_resources(self):
        """Returns resources that are related to the current resource, i.e. live,
        public articles and videos which have the same topics."""
        topic_pks = [topic.topic.pk for topic in self.topics.all()]
        return get_combined_articles_and_videos(
            self, topics__topic__pk__in=topic_pks)

    def has_speaker(self, person):
        for speaker in self.speakers:  # pylint: disable=not-an-iterable
            if str(speaker.value) == str(person.title):
                return True
        return False
Exemplo n.º 27
0
class MoviePage(Page):

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

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

    director = models.CharField(max_length=255, null=True, blank=True)
    country = models.CharField(max_length=255, null=True,blank=True)
    releaseDate = models.DateField(null=True,blank=True)  # releaseYear enough??
    movieType = models.CharField(max_length=255, null=True, blank=True)
    spokenLanguage = models.CharField(max_length=255, null=True, blank=True)
    subtitleLanguage = models.CharField(max_length=255, null=True, blank=True)
    lengthInMinutes = models.IntegerField(null=True, blank=True)
    minimumAge = models.IntegerField(null=True, blank=True)
    premiere = models.BooleanField(default=False)
    showStartDate = models.DateField(null=True, blank=True)
    showEndDate = models.DateField(null=True, blank=True)
    classifications = ParentalManyToManyField(KijkWijzerClassification, blank=True)


    trailer = models.URLField("Trailer", blank=True, null=True)

    doubleBillMovie = models.ForeignKey(
        'MoviePage',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
    )

    body = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('image', ImageChooserBlock()),
        ('quotation', blocks.StructBlock([
            ('text', blocks.TextBlock()),
            ('author', blocks.CharBlock()),
        ])),
    ], blank=True, null=True)



    content_panels = Page.content_panels + [
        FieldPanel('director'),
        FieldPanel('country'),
        FieldPanel('releaseDate'),
        FieldPanel('movieType'),
        FieldPanel('spokenLanguage'),
        FieldPanel('subtitleLanguage'),
        FieldPanel('lengthInMinutes'),
        FieldPanel('minimumAge'),
        FieldPanel('premiere'),

        PageChooserPanel('doubleBillMovie', 'home.MoviePage'),

        ImageChooserPanel('moviePoster'),
        ImageChooserPanel('movieBackDrop'),

        FieldPanel('trailer'),
        InlinePanel('movieDates', label="Movie dates"),
        InlinePanel('externalLinks', label="External links"),
        FieldPanel('classifications',widget=forms.CheckboxSelectMultiple),
        # InlinePanel( 'classifications', label="Categories"),

        StreamFieldPanel('body'),

    ]

    api_fields = [
        APIField('director'),
        APIField('country'),
        APIField('body'),
        APIField('releaseDate'),
        APIField('movieType'),
        APIField('spokenLanguage'),
        APIField('subtitleLanguage'),
        APIField('lengthInMinutes'),
        APIField('premiere'),
        APIField('minimumAge'),
        APIField('doubleBillMovie'),
        APIField('movieDates', serializer=MovieDateSerializer(many=True, read_only=True)),
        APIField('externalLinks', serializer=ExternalLinkSerializer(many=True, read_only=True)),
        APIField('moviePoster'),
        APIField('moviePosterThumb', serializer=ImageRenditionField('fill-100x100', source='moviePoster')),
        APIField('movieBackDrop'),
        APIField('trailer'),
        APIField('classifications', serializer=KijkWijzerClassificationSerializer(many=True, read_only=True)),

    ]

    def get_start_date(self, current_date, date_to_compare):
        return date_to_compare if (current_date is None) or (date_to_compare < current_date) else current_date

    def get_end_date(self, current_date, date_to_compare):
        return date_to_compare if (current_date is None) or (date_to_compare > current_date) else current_date

    def save(self, *args, **kwargs):
        start_date_time = None
        end_date_time = None
        for movie_date in self.movieDates.all():
            start_date_time = self.get_start_date( start_date_time, movie_date.date)
            end_date_time = self.get_end_date( end_date_time, movie_date.date)

        if start_date_time and end_date_time:
            self.showStartDate = start_date_time.date()
            self.showEndDate = end_date_time.date()

        super().save(*args, **kwargs)  # Call the "real" save() method.
class SeriesPage(Page):
    """Series page"""
    template = "series/series_page.html"

    sub_title = models.CharField(blank=False, null=False, max_length=255)
    produced_from = models.PositiveIntegerField(null=False, blank=False)
    produced_to = models.PositiveIntegerField(null=True, blank=True)
    description = RichTextField(
        features=['h3', 'h4', 'ol', 'ul', 'bold', 'italic', 'link'],
        null=True,
        blank=True)
    hero = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        help_text=
        "The hero image is used in the page header as well as in the information description of the series."
    )
    poster = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        help_text=
        "The poster image is used in some promotional listings of the series.")
    multi_season_series = models.BooleanField(
        blank=True,
        null=False,
        default=False,
        verbose_name="Multi season series",
        help_text="Is this a part of a multi season series?")
    content = StreamField([
        ('related_series', PromotedSeriesBlock()),
    ],
                          null=True,
                          blank=True)

    api_fields = [
        APIField('sub_title'),
        APIField('produced_from'),
        APIField('produced_to'),
        APIField('description'),
        APIField('hero', serializer=ImageRenditionField('fill-1920x780')),
        APIField('poster', serializer=ImageRenditionField('width-218')),
        APIField('episodes'),
        APIField('content'),
    ]

    content_panels = Page.content_panels + [
        MultiFieldPanel([
            FieldPanel('sub_title'),
            ImageChooserPanel('hero'),
        ],
                        heading="Header"),
        MultiFieldPanel([
            FieldPanel('description'),
            FieldPanel('produced_from'),
            FieldPanel('produced_to'),
            ImageChooserPanel('poster'),
            FieldPanel('multi_season_series'),
        ],
                        heading="Information"),
        InlinePanel('episodes', label="Episodes"),
        StreamFieldPanel('content'),
    ]

    @property
    def has_new_episodes(self):
        new_episodes = self.episodes.filter(is_new=True)
        return len(new_episodes) > 0

    parent_page_types = ['series.SeriesIndexPage']
    subpage_types = []

    def get_admin_display_title(self):
        return '{} – {}'.format(super().get_admin_display_title(),
                                self.sub_title)

    def __str__(self):
        return self.title

    class Meta:  # noqa
        verbose_name_plural = "Series"
Exemplo n.º 29
0
class SectionedRichTextPage(Page):
    content_panels = [
        FieldPanel('title', classname="full title"),
        InlinePanel('sections')
    ]
Exemplo n.º 30
0
class FixtureDetailPage(Page):
    """Fixture detail page."""

    subpage_types = []

    competition = models.CharField(
        max_length=100,
        blank=False,
        null=True,
        help_text='Name of Competition e.g. Div 2, Cup QF etc.',
    )

    hometeam = models.CharField(
        max_length=200,
        blank=False,
        null=False,
        help_text='Home team name',
    )
    hometeam_image = models.ForeignKey(
        "wagtailimages.Image",
        blank=False,
        null=True,
        related_name="+",
        on_delete=models.SET_NULL,
        help_text='Home team Logo',
    )

    awayteam = models.CharField(
        max_length=200,
        blank=False,
        null=False,
        help_text='AWay Team Name',
    )
    awayteam_image = models.ForeignKey(
        "wagtailimages.Image",
        blank=False,
        null=True,
        related_name="+",
        on_delete=models.SET_NULL,
        help_text='Away Team Logo',
    )

    fixture_date_time = models.CharField(
        max_length=40,
        blank=False,
        null=False,
        help_text='Date and Time of Fixture',
    )

    fixture_location = models.CharField(
        max_length=100,
        blank=False,
        null=False,
        help_text='Fixture location',
    )

    fixture_video = models.URLField(
        blank=True,
        null=True,
        help_text='Enter the url link to the match video. (optional)',
    )

    HT_FT_PTS = models.IntegerField(null=True, blank=True)
    AT_FT_PTS = models.IntegerField(null=True, blank=True)
    HT_HT_PTS = models.IntegerField(null=True, blank=True)
    AT_HT_PTS = models.IntegerField(null=True, blank=True)

    Home_Team_Scorers = RichTextField(features=["bold", "italic"],
                                      null=True,
                                      blank=True)
    Away_Team_Scorers = RichTextField(features=["bold", "italic"],
                                      null=True,
                                      blank=True)

    Match_Officials = RichTextField(features=["bold", "italic"],
                                    null=True,
                                    blank=True)
    Match_Report = RichTextField(features=["bold", "italic", "link"],
                                 null=True,
                                 blank=True)

    content_panels = Page.content_panels + [
        FieldPanel("competition"),
        FieldPanel("hometeam"),
        ImageChooserPanel("hometeam_image"),
        FieldPanel("awayteam"),
        ImageChooserPanel("awayteam_image"),
        FieldPanel("fixture_date_time"),
        FieldPanel("fixture_location"),
        MultiFieldPanel([
            InlinePanel("fixture_status_selector",
                        label="Fixture Status",
                        min_num=1,
                        max_num=1)
        ],
                        heading="Fixture Status"),
        FieldPanel("fixture_video"),
        FieldRowPanel([
            FieldPanel("HT_FT_PTS"),
            FieldPanel("HT_HT_PTS"),
            FieldPanel("AT_FT_PTS"),
            FieldPanel("AT_HT_PTS"),
        ]),
        FieldPanel("Home_Team_Scorers"),
        FieldPanel("Away_Team_Scorers"),
        FieldPanel("Match_Officials"),
        FieldPanel("Match_Report")
    ]