Ejemplo n.º 1
0
class DataParser:
    def __init__(self, content_type, single_entry=False):
        self.content_type = content_type
        self.data_parsed = []
        self.renderer = RichTextRenderer()
        self.single_entry = single_entry

    def set_data(self, data):
        self.data = data

    def parse(self):
        self.__parse_default()
        if (self.single_entry == True):
            return self.data_parsed[0]
        else:
            return self.data_parsed

    def __parse_default(self):
        items = self.data['items']
        for item in items:
            parsed_item = item.get('fields')
            self.data_parsed.append(self.__parse_document_field(parsed_item))

    def __parse_document_field(self, item):
        parsed_item = {}
        for key, value in item.items():
            if (isinstance(value, dict)):
                #is not None means has nodeType value
                if (value.get('nodeType')
                        and value.get('nodeType') == 'document'):
                    list_content = self.renderer.render(value)
                    value = list_content
            parsed_item.update({key: value})

        return parsed_item
Ejemplo n.º 2
0
    def test_render_with_defaults(self):
        renderer = RichTextRenderer()

        self.assertEqual(
            renderer.render(full_document),
            "\n".join([
                "<h1>Some heading</h1>",
                "<p></p>",
                "<div>{0}</div>".format({
                    "sys": {
                        "id": "49rofLvvxCOiIMIi6mk8ai",
                        "type": "Link",
                        "linkType": "Entry",
                    }
                }),
                "<h2>Some subheading</h2>",
                "<p><b>Some bold</b></p>",
                "<p><i>Some italics</i></p>",
                "<p><u>Some underline</u></p>",
                "<p></p>",
                "<p></p>",
                "<div>{0}</div>".format({
                    "sys": {
                        "id": "5ZF9Q4K6iWSYIU2OUs0UaQ",
                        "type": "Link",
                        "linkType": "Entry",
                    }
                }),
                "<p></p>",
                "<p>Some raw content</p>",
                "<p></p>",
                "<p>An unpublished embed:</p>",
                "<p></p>",
                "<div>{0}</div>".format({
                    "sys": {
                        "id": "q2hGXkd5tICym64AcgeKK",
                        "type": "Link",
                        "linkType": "Entry",
                    }
                }),
                "<p>Some more content</p>",
            ]),
        )
Ejemplo n.º 3
0
MAP_KEY = os.environ.get("MAP_KEY")
DEBUG_STATUS = os.environ.get("DEBUG_STATUS")
ENV = os.environ.get("ENV")

client = contentful.Client(SPACE_ID,
                           DELIVERY_API_KEY,
                           API_URL,
                           environment=ENV)

BaseBlockEntryRenderer.__RENDERERS__ += [
    locationBlockEntryRenderer,
    buttonEntryRenderer,
]

renderer = RichTextRenderer({
    "embedded-entry-block": BaseBlockEntryRenderer,
    "embedded-entry-inline": BaseInlineRenderer,
})

app = Flask(__name__)
Markdown(app)


@app.route("/")
def home_page():
    entry = client.entry("1l3EHYzPbgf9UUV0oEyTDs")

    return render_template(
        "home.html",
        renderer=renderer,
        title=entry.page_title,
        page_components=entry.page_component,
Ejemplo n.º 4
0
class ContentfulPage:
    # TODO: List: stop list items from being wrapped in paragraph tags
    # TODO: Error/ Warn / Transform links to allizom
    client = get_client()
    _renderer = RichTextRenderer({
        "hyperlink": LinkRenderer,
        "bold": StrongRenderer,
        "italic": EmphasisRenderer,
        "unordered-list": UlRenderer,
        "ordered-list": OlRenderer,
        "list-item": LiRenderer,
        "paragraph": PRenderer,
        "embedded-entry-inline": InlineEntryRenderer,
        "embedded-asset-block": AssetBlockRenderer,
    })
    SPLIT_LAYOUT_CLASS = {
        "Even": "",
        "Narrow": "mzp-l-split-body-narrow",
        "Wide": "mzp-l-split-body-wide",
    }

    SPLIT_MEDIA_WIDTH_CLASS = {
        "Fill available width": "",
        "Fill available height": "mzp-l-split-media-constrain-height",
        "Overflow container": "mzp-l-split-media-overflow",
    }

    SPLIT_V_ALIGN_CLASS = {
        "Top": "mzp-l-split-v-start",
        "Center": "mzp-l-split-v-center",
        "Bottom": "mzp-l-split-v-end",
    }

    SPLIT_H_ALIGN_CLASS = {
        "Left": "mzp-l-split-h-start",
        "Center": "mzp-l-split-h-center",
        "Right": "mzp-l-split-h-end",
    }

    SPLIT_POP_CLASS = {
        "None": "",
        "Both": "mzp-l-split-pop",
        "Top": "mzp-l-split-pop-top",
        "Bottom": "mzp-l-split-pop-bottom",
    }
    CONTENT_TYPE_MAP = {
        "componentHero": {
            "proc": "get_hero_data",
            "css": "c-hero",
        },
        "componentSectionHeading": {
            "proc": "get_section_data",
            "css": "c-section-heading",
        },
        "componentSplitBlock": {
            "proc": "get_split_data",
            "css": "c-split",
        },
        "componentCallout": {
            "proc": "get_callout_data",
            "css": "c-call-out",
        },
        "layout2Cards": {
            "proc": "get_card_layout_data",
            "css": "t-card-layout",
            "js": "c-card"
        },
        "layout3Cards": {
            "proc": "get_card_layout_data",
            "css": "t-card-layout",
            "js": "c-card"
        },
        "layout4Cards": {
            "proc": "get_card_layout_data",
            "css": "t-card-layout",
            "js": "c-card"
        },
        "layout5Cards": {
            "proc": "get_card_layout_data",
            "css": "t-card-layout",
            "js": "c-card"
        },
        "layoutPictoBlocks": {
            "proc": "get_picto_layout_data",
            "css": ("c-picto", "t-multi-column"),
        },
        "textOneColumn": {
            "proc": "get_text_column_data_1",
            "css": "t-multi-column",
        },
        "textTwoColumns": {
            "proc": "get_text_column_data_2",
            "css": "t-multi-column",
        },
        "textThreeColumns": {
            "proc": "get_text_column_data_3",
            "css": "t-multi-column",
        },
        "textFourColumns": {
            "proc": "get_text_column_data_4",
            "css": "t-multi-column",
        },
    }

    def __init__(self, request, page_id):
        set_current_request(request)
        self.request = request
        self.page_id = page_id
        self.locale = get_locale(request)

    @cached_property
    def page(self):
        return self.client.entry(
            self.page_id,
            {
                "include": 10,
                "locale": self.locale,
                # ie, get ONLY the page for the specificed locale, as long as
                # the locale doesn't have a fallback configured in Contentful
            },
        )

    def render_rich_text(self, node):
        return self._renderer.render(node) if node else ""

    def _get_preview_image_from_fields(self, fields):
        if "preview_image" in fields:
            # TODO request proper size image
            preview_image_url = fields["preview_image"].fields().get(
                "file", {}).get("url", {})
            if preview_image_url:
                return f"https:{preview_image_url}"

    def _get_info_data__slug_title_blurb(self, entry_fields, seo_fields):

        if self.page.content_type.id == COMPOSE_MAIN_PAGE_TYPE:
            # This means we're dealing with a Compose-structured setup,
            # and the slug lives not on the Entry, nor the SEO object
            # but just on the top-level Compose `page`
            slug = self.page.fields().get("slug")
        else:
            # Non-Compose pages
            slug = entry_fields.get(
                "slug", "home")  # TODO: check if we can use a better fallback

        title = getattr(self.page, "title", "")
        title = entry_fields.get("preview_title", title)
        blurb = entry_fields.get("preview_blurb", "")

        if seo_fields:
            # Defer to SEO fields for blurb if appropriate.
            blurb = seo_fields.get("description", "")

        return {
            "slug": slug,
            "title": title,
            "blurb": blurb,
        }

    def _get_info_data__category_tags_classification(self, entry_fields,
                                                     page_type):

        data = {}

        # TODO: Check with plans for Contentful use - we may
        # be able to relax this check and use it for page types
        # once we're in all-Compose mode
        if page_type == CONTENT_TYPE_PAGE_RESOURCE_CENTER:
            if "category" in entry_fields:
                data["category"] = entry_fields["category"]
            if "tags" in entry_fields:
                data["tags"] = entry_fields["tags"]
            if "product" in entry_fields:
                # NB: this is a re-mapping with an eye on flexibility - pages may not always have
                # a 'product' key, but they might have something regarding overall classification
                data["classification"] = entry_fields["product"]
        return data

    def _get_info_data__theme_campaign(self, entry_fields, slug):
        _folder = entry_fields.get("folder", "")
        _in_firefox = "firefox-" if "firefox" in _folder else ""
        campaign = f"{_in_firefox}{slug}"
        theme = "firefox" if "firefox" in _folder else "mozilla"
        return {
            "theme": theme,
            "campaign": campaign,
        }

    def _get_info_data__locale(self, page_type, entry_fields, entry_obj):
        # TODO: update this once we have a robust locale field available (ideally
        # via Compose's parent `page`), because double-purposing the "name" field
        # is a bit too brittle.
        if page_type == "pageHome":
            locale = entry_fields["name"]
        else:
            locale = entry_obj.sys["locale"]
        return {"locale": locale}

    def get_info_data(self, entry_obj, seo_obj=None):
        # TODO, need to enable connectors
        entry_fields = entry_obj.fields()
        if seo_obj:
            seo_fields = seo_obj.fields()
        else:
            seo_fields = None

        page_type = entry_obj.content_type.id

        data = {}

        data.update(
            self._get_info_data__slug_title_blurb(entry_fields, seo_fields))
        data.update(
            self._get_info_data__theme_campaign(entry_fields, data["slug"]))
        data.update(
            self._get_info_data__locale(page_type, entry_fields, entry_obj))
        campaign = data.pop("campaign")
        data.update({
            # eg www.mozilla.org-firefox-accounts or www.mozilla.org-firefox-sync
            "utm_source": f"www.mozilla.org-{campaign}",
            "utm_campaign": campaign,  # eg firefox-sync
        })

        _preview_image = self._get_preview_image_from_fields(entry_fields)
        if _preview_image:
            data["image"] = _preview_image

        if seo_fields:
            _preview_image = self._get_preview_image_from_fields(seo_fields)

            _seo_fields = deepcopy(
                seo_fields)  # NB: don't mutate the source dict
            if _preview_image:
                _seo_fields["image"] = _preview_image

            # We don't need the preview_image key if we've had it in the past, and
            # if reading it fails then we don't want it sticking around, either
            _seo_fields.pop("preview_image", None)
            data.update({"seo": _seo_fields})

        data.update(
            self._get_info_data__category_tags_classification(
                entry_fields,
                page_type,
            ))

        return data

    def get_content(self):
        # Check if it is a page or a connector, or a Compose page type

        entry_type = self.page.content_type.id
        seo_obj = None
        if entry_type == COMPOSE_MAIN_PAGE_TYPE:
            # Contentful Compose page, linking to content and SEO models
            entry_obj = self.page.content  # The page with the actual content
            seo_obj = self.page.seo  # The SEO model
            # Note that the slug lives on self.page, not the seo_obj.
        elif entry_type.startswith("page"):
            entry_obj = self.page
        elif entry_type == "connectHomepage":
            # Legacy - TODO: remove me once we're no longer using Connect: Homepage
            entry_obj = self.page.fields()["entry"]
        else:
            raise ValueError(f"{entry_type} is not a recognized page type")

        if not entry_obj:
            raise Exception(
                f"No 'Entry' detected for {self.page.content_type.id}")

        self.request.page_info = self.get_info_data(
            entry_obj,
            seo_obj,
        )
        page_type = entry_obj.content_type.id
        page_css = set()
        page_js = set()
        fields = entry_obj.fields()
        content = None
        entries = []

        def proc(item):
            content_type = item.sys.get("content_type").id
            ctype_info = self.CONTENT_TYPE_MAP.get(content_type)
            if ctype_info:
                processor = getattr(self, ctype_info["proc"])
                entries.append(processor(item))
                css = ctype_info.get("css")
                if css:
                    if isinstance(css, str):
                        css = (css, )

                    page_css.update(css)

                js = ctype_info.get("js")
                if js:
                    if isinstance(js, str):
                        js = (js, )

                    page_js.update(js)

        if page_type == CONTENT_TYPE_PAGE_GENERAL:
            # look through all entries and find content ones
            for key, value in fields.items():
                if key == "component_hero":
                    proc(value)
                elif key == "body":
                    entries.append(self.get_text_data(value))
                elif key == "component_callout":
                    proc(value)
        elif page_type == CONTENT_TYPE_PAGE_RESOURCE_CENTER:
            # TODO: can we actually make this generic? Poss not: main_content is a custom field name
            _content = fields.get("main_content", {})
            entries.append(self.get_text_data(_content))
        else:
            # This covers pageVersatile, pageHome, etc
            content = fields.get("content")

        if content:
            # get components from content
            for item in content:
                proc(item)

        return {
            "page_type": page_type,
            "page_css": list(page_css),
            "page_js": list(page_js),
            "info": self.request.page_info,
            "entries": entries,
        }

    def get_text_data(self, value):
        data = {
            "component": "text",
            "body": self.render_rich_text(value),
            "width_class": _get_width_class("Medium")
        }  # TODO

        return data

    def get_hero_data(self, entry_obj):
        fields = entry_obj.fields()

        hero_image_url = _get_image_url(fields["image"], 800)
        hero_reverse = fields.get("image_side")
        hero_body = self.render_rich_text(fields.get("body"))

        product_class = _get_product_class(fields.get(
            "product_icon")) if fields.get("product_icon") and fields.get(
                "product_icon") != "None" else ""
        data = {
            "component":
            "hero",
            "theme_class":
            _get_theme_class(fields.get("theme")),
            "product_class":
            product_class,
            "title":
            fields.get("heading"),
            "tagline":
            fields.get("tagline"),
            "body":
            hero_body,
            "image":
            hero_image_url,
            "image_class":
            "mzp-l-reverse" if hero_reverse == "Left" else "",
            "include_cta":
            True if fields.get("cta") else False,
            "cta":
            _make_cta_button(fields.get("cta")) if fields.get("cta") else "",
        }

        return data

    def get_section_data(self, entry_obj):
        fields = entry_obj.fields()

        data = {
            "component": "sectionHeading",
            "heading": fields.get("heading"),
        }

        return data

    def get_split_data(self, entry_obj):
        fields = entry_obj.fields()

        def get_split_class():
            block_classes = [
                "mzp-l-split-reversed"
                if fields.get("image_side") == "Left" else "",
                self.SPLIT_LAYOUT_CLASS.get(fields.get("body_width"), ""),
                self.SPLIT_POP_CLASS.get(fields.get("image_pop"), ""),
            ]
            return " ".join(block_classes)

        def get_body_class():
            body_classes = [
                self.SPLIT_V_ALIGN_CLASS.get(
                    fields.get("body_vertical_alignment"), ""),
                self.SPLIT_H_ALIGN_CLASS.get(
                    fields.get("body_horizontal_alignment"), ""),
            ]
            return " ".join(body_classes)

        def get_media_class():
            media_classes = [
                self.SPLIT_MEDIA_WIDTH_CLASS.get(fields.get("image_width"),
                                                 ""),
                self.SPLIT_V_ALIGN_CLASS.get(
                    fields.get("image_vertical_alignment"), ""),
                self.SPLIT_H_ALIGN_CLASS.get(
                    fields.get("image_horizontal_alignment"), ""),
            ]
            return " ".join(media_classes)

        def get_mobile_class():
            mobile_display = fields.get("mobile_display")
            if not mobile_display:
                return ""

            mobile_classes = [
                "mzp-l-split-center-on-sm-md"
                if "Center content" in mobile_display else "",
                "mzp-l-split-hide-media-on-sm-md"
                if "Hide image" in mobile_display else "",
            ]
            return " ".join(mobile_classes)

        split_image_url = _get_image_url(fields["image"], 800)

        data = {
            "component": "split",
            "block_class": get_split_class(),
            "theme_class": _get_theme_class(fields.get("theme")),
            "body_class": get_body_class(),
            "body": self.render_rich_text(fields.get("body")),
            "media_class": get_media_class(),
            "image": split_image_url,
            "mobile_class": get_mobile_class(),
        }
        return data

    def get_callout_data(self, entry_obj):
        fields = entry_obj.fields()

        data = {
            "component":
            "callout",
            "theme_class":
            _get_theme_class(fields.get("theme")),
            "product_class":
            _get_product_class(fields.get("product_icon"))
            if fields.get("product_icon") else "",
            "title":
            fields.get("heading"),
            "body":
            self.render_rich_text(fields.get("body"))
            if fields.get("body") else "",
            "cta":
            _make_cta_button(fields.get("cta")),
        }

        return data

    def get_card_data(self, entry_obj, aspect_ratio):
        # need a fallback aspect ratio
        aspect_ratio = aspect_ratio or "16:9"
        fields = entry_obj.fields()
        card_body = self.render_rich_text(
            fields.get("body")) if fields.get("body") else ""
        image_url = highres_image_url = ""

        if "image" in fields:
            card_image = fields.get("image")
            # TODO smaller image files when layout allows it
            if card_image:
                highres_image_url = _get_card_image_url(
                    card_image, 800, aspect_ratio)
                image_url = _get_card_image_url(card_image, 800, aspect_ratio)

        if "you_tube" in fields:
            # TODO: add youtube JS to page_js
            youtube_id = _get_youtube_id(fields.get("you_tube"))
        else:
            youtube_id = ""

        data = {
            "component":
            "card",
            "heading":
            fields.get("heading"),
            "tag":
            fields.get("tag"),
            "link":
            fields.get("link"),
            "body":
            card_body,
            "aspect_ratio":
            _get_aspect_ratio_class(aspect_ratio) if image_url != "" else "",
            "highres_image_url":
            highres_image_url,
            "image_url":
            image_url,
            "youtube_id":
            youtube_id,
        }

        return data

    def get_large_card_data(self, entry_obj, card_obj):
        fields = entry_obj.fields()

        # get card data
        card_data = self.get_card_data(card_obj, "16:9")

        # large card data
        large_card_image = fields.get("image")
        if large_card_image:
            highres_image_url = _get_card_image_url(large_card_image, 1860,
                                                    "16:9")
            image_url = _get_card_image_url(large_card_image, 1860, "16:9")

            # over-write with large values
            card_data["component"] = "large_card"
            card_data["highres_image_url"] = highres_image_url
            card_data["image_url"] = image_url

        return card_data

    def get_card_layout_data(self, entry_obj):
        fields = entry_obj.fields()
        aspect_ratio = fields.get("aspect_ratio")
        layout = entry_obj.sys.get("content_type").id

        data = {
            "component": "cardLayout",
            "layout_class": _get_layout_class(layout),
            "aspect_ratio": aspect_ratio,
            "cards": [],
        }

        follows_large_card = False
        if layout == "layout5Cards":
            card_layout_obj = fields.get("large_card")
            card_obj = fields.get("large_card").fields().get("card")
            large_card_data = self.get_large_card_data(card_layout_obj,
                                                       card_obj)

            data.get("cards").append(large_card_data)
            follows_large_card = True

        cards = fields.get("content")
        for card in cards:
            if follows_large_card:
                this_aspect = "1:1"
                follows_large_card = False
            else:
                this_aspect = aspect_ratio
            card_data = self.get_card_data(card, this_aspect)
            data.get("cards").append(card_data)

        return data

    def get_picto_data(self, picto_obj, image_width):

        fields = picto_obj.fields()
        body = self.render_rich_text(
            fields.get("body")) if fields.get("body") else False

        if "icon" in fields:
            picto_image = fields.get("icon")
            image_url = _get_image_url(picto_image, image_width)
        else:
            image_url = ""  # TODO: this should cause an error, the macro requires an image

        return {
            "component": "picto",
            "heading": fields.get("heading"),
            "body": body,
            "image_url": image_url,
        }

    def get_picto_layout_data(self, entry):
        PICTO_ICON_SIZE = {
            "Small": 32,
            "Medium": 48,
            "Large": 64,
            "Extra Large": 96,
            "Extra Extra Large": 192,
        }
        fields = entry.fields()

        # layout = entry.sys.get('content_type').id

        def get_layout_class():
            column_class = _get_column_class(str(fields.get("blocks_per_row")))
            layout_classes = [
                _get_width_class(fields.get("width")),
                column_class or "3",
                "mzp-t-picto-side"
                if fields.get("icon_position") == "Side" else "",
                "mzp-t-picto-center"
                if fields.get("block_alignment") == "Center" else "",
                _get_theme_class(fields.get("theme")),
            ]

            return " ".join(layout_classes)

        image_width = PICTO_ICON_SIZE.get(
            fields.get("icon_size")) if fields.get(
                "icon_size") else PICTO_ICON_SIZE.get("Large")

        data = {
            "component":
            "pictoLayout",
            "layout_class":
            get_layout_class(),
            "heading_level":
            fields.get("heading_level")[1:]
            if fields.get("heading_level") else 3,
            "image_width":
            image_width,
            "pictos": [],
        }

        pictos = fields.get("content")
        for picto_obj in pictos:
            picto_data = self.get_picto_data(picto_obj, image_width)
            data.get("pictos").append(picto_data)

        return data

    def get_text_column_data(self, cols, entry_obj):
        fields = entry_obj.fields()

        def get_content_class():
            content_classes = [
                _get_width_class(fields.get("width")),
                _get_column_class(str(cols)),
                _get_theme_class(fields.get("theme")),
                "mzp-u-center"
                if fields.get("block_alignment") == "Center" else "",
            ]

            return " ".join(content_classes)

        data = {
            "component": "textColumns",
            "layout_class": get_content_class(),
            "content": [self.render_rich_text(fields.get("body_column_one"))],
        }

        if cols > 1:
            data["content"].append(
                self.render_rich_text(fields.get("body_column_two")))
        if cols > 2:
            data["content"].append(
                self.render_rich_text(fields.get("body_column_three")))
        if cols > 3:
            data["content"].append(
                self.render_rich_text(fields.get("body_column_four")))

        return data

    get_text_column_data_1 = partialmethod(get_text_column_data, 1)
    get_text_column_data_2 = partialmethod(get_text_column_data, 2)
    get_text_column_data_3 = partialmethod(get_text_column_data, 3)
    get_text_column_data_4 = partialmethod(get_text_column_data, 4)
Ejemplo n.º 5
0
 def __init__(self, content_type, single_entry=False):
     self.content_type = content_type
     self.data_parsed = []
     self.renderer = RichTextRenderer()
     self.single_entry = single_entry
Ejemplo n.º 6
0
def article(slug):
    article = Contentful.get_article_by_slug(slug)
    renderer = RichTextRenderer()
    article.html = renderer.render(article.content)
    return render_template('article.html', navbar=navbar, article=article)
Ejemplo n.º 7
0
    def test_render_with_all_renderers_overridden_for_markdown(self):
        self.maxDiff = None
        renderer = RichTextRenderer({
            "heading-1": HeadingOneMarkdownRenderer,
            "heading-2": HeadingTwoMarkdownRenderer,
            "paragraph": ParagraphMarkdownRenderer,
            "embedded-entry-block": EntryBlockMarkdownRenderer,
            "bold": BoldMarkdownRenderer,
            "italic": ItalicMarkdownRenderer,
            "underline": UnderlineMarkdownRenderer,
        })

        self.assertEqual(
            renderer.render(full_document),
            "\n".join([
                "# Some heading",
                "",
                "",
                "",
                "",
                "```",
                "{0}".format({
                    "sys": {
                        "id": "49rofLvvxCOiIMIi6mk8ai",
                        "type": "Link",
                        "linkType": "Entry",
                    }
                }),
                "```",
                "",
                "## Some subheading",
                "",
                "**Some bold**",
                "",
                "",
                "*Some italics*",
                "",
                "",
                "__Some underline__",
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                "```",
                "{0}".format({
                    "sys": {
                        "id": "5ZF9Q4K6iWSYIU2OUs0UaQ",
                        "type": "Link",
                        "linkType": "Entry",
                    }
                }),
                "```",
                "",
                "",
                "",
                "",
                "",
                "Some raw content",
                "",
                "",
                "",
                "",
                "",
                "An unpublished embed:",
                "",
                "",
                "",
                "",
                "",
                "```",
                "{0}".format({
                    "sys": {
                        "id": "q2hGXkd5tICym64AcgeKK",
                        "type": "Link",
                        "linkType": "Entry",
                    }
                }),
                "```",
                "",
                "",
                "Some more content",
                "",
            ]),
        )
Ejemplo n.º 8
0
    def test_render_with_emojis(self):
        renderer = RichTextRenderer()

        self.assertEqual(renderer.render(mock_document_with_unicode),
                         "\n".join(["<p>😇</p>"]))
Ejemplo n.º 9
0
    def test_null_renderer_will_raise_an_error_if_unknown_node_type_is_not_mapped(
            self):
        renderer = RichTextRenderer()

        with self.assertRaises(Exception):
            renderer.render(mock_unknown_node)
Ejemplo n.º 10
0
from core import app
from flask import request, abort
from flask import Markup

from dateutil import parser
from markdown import markdown

import urllib

from rich_text_renderer import RichTextRenderer

renderer = RichTextRenderer()


@app.template_filter('date')
def date_filter(date, format='%b %d, %Y'):
    if isinstance(date, str):
        date = parser.parse(date)

    return date.strftime(format)


@app.template_filter('percentage')
def percentage_filter(number):
    return '%d%%' % (number * 100)


@app.template_filter('url')
def url_filter(url):
    if not url.startswith('http'):
        return 'http://' + url