Exemplo n.º 1
0
def render_markdown_path(markdown_file_path: str,
                         context: Mapping[str, Any] = {},
                         pure_markdown: bool = False) -> str:
    """Given a path to a markdown file, return the rendered html.

    Note that this assumes that any HTML in the markdown file is
    trusted; it is intended to be used for documentation, not user
    data."""

    # We set this global hackishly
    from zerver.lib.bugdown.help_settings_links import set_relative_settings_links
    set_relative_settings_links(bool(context.get('html_settings_links')))
    from zerver.lib.bugdown.help_relative_links import set_relative_help_links
    set_relative_help_links(bool(context.get('html_settings_links')))

    global md_extensions
    global md_macro_extension
    if md_extensions is None:
        md_extensions = [
            markdown.extensions.extra.makeExtension(),
            markdown.extensions.toc.makeExtension(),
            markdown.extensions.admonition.makeExtension(),
            markdown.extensions.codehilite.makeExtension(
                linenums=False,
                guess_lang=False,
            ),
            zerver.lib.bugdown.fenced_code.makeExtension(
                run_content_validators=context.get('run_content_validators',
                                                   False), ),
            zerver.lib.bugdown.api_arguments_table_generator.makeExtension(
                base_path='templates/zerver/api/'),
            zerver.lib.bugdown.api_return_values_table_generator.makeExtension(
                base_path='templates/zerver/api/'),
            zerver.lib.bugdown.nested_code_blocks.makeExtension(),
            zerver.lib.bugdown.tabbed_sections.makeExtension(),
            zerver.lib.bugdown.help_settings_links.makeExtension(),
            zerver.lib.bugdown.help_relative_links.makeExtension(),
            zerver.lib.bugdown.help_emoticon_translations_table.makeExtension(
            ),
        ]
    if md_macro_extension is None:
        md_macro_extension = zerver.lib.bugdown.include.makeExtension(
            base_path='templates/zerver/help/include/')
    extensions = md_extensions
    if 'api_url' in context:
        # We need to generate the API code examples extension each
        # time so the `api_url` config parameter can be set dynamically.
        #
        # TODO: Convert this to something more efficient involving
        # passing the API URL as a direct parameter.
        extensions = extensions + [
            zerver.openapi.markdown_extension.makeExtension(
                api_url=context["api_url"], )
        ]
    if not any(doc in markdown_file_path for doc in docs_without_macros):
        extensions = extensions + [md_macro_extension]

    md_engine = markdown.Markdown(extensions=extensions)
    md_engine.reset()

    jinja = engines['Jinja2']

    try:
        # By default, we do both Jinja2 templating and markdown
        # processing on the file, to make it easy to use both Jinja2
        # context variables and markdown includes in the file.
        markdown_string = jinja.env.loader.get_source(jinja.env,
                                                      markdown_file_path)[0]
    except TemplateNotFound as e:
        if pure_markdown:
            # For files such as /etc/zulip/terms.md where we don't intend
            # to use Jinja2 template variables, we still try to load the
            # template using Jinja2 (in case the file path isn't absolute
            # and does happen to be in Jinja's recognized template
            # directories), and if that fails, we try to load it directly
            # from disk.
            with open(markdown_file_path) as fp:
                markdown_string = fp.read()
        else:
            raise e

    html = md_engine.convert(markdown_string)
    rendered_html = jinja.from_string(html).render(context)

    return mark_safe(rendered_html)
Exemplo n.º 2
0
def render_markdown_path(markdown_file_path: str,
                         context: Optional[Dict[Any, Any]] = None,
                         pure_markdown: Optional[bool] = False) -> str:
    """Given a path to a markdown file, return the rendered html.

    Note that this assumes that any HTML in the markdown file is
    trusted; it is intended to be used for documentation, not user
    data."""

    if context is None:
        context = {}

    # We set this global hackishly
    from zerver.lib.bugdown.help_settings_links import set_relative_settings_links
    set_relative_settings_links(bool(context.get('html_settings_links')))
    from zerver.lib.bugdown.help_relative_links import set_relative_help_links
    set_relative_help_links(bool(context.get('html_settings_links')))

    global md_extensions
    global md_macro_extension
    if md_extensions is None:
        md_extensions = [
            markdown.extensions.extra.makeExtension(),
            markdown.extensions.toc.makeExtension(),
            markdown.extensions.admonition.makeExtension(),
            markdown.extensions.codehilite.makeExtension(linenums=False,
                                                         guess_lang=False),
            zerver.lib.bugdown.fenced_code.makeExtension(),
            zerver.lib.bugdown.api_arguments_table_generator.makeExtension(
                base_path='templates/zerver/api/'),
            zerver.lib.bugdown.api_code_examples.makeExtension(),
            zerver.lib.bugdown.nested_code_blocks.makeExtension(),
            zerver.lib.bugdown.tabbed_sections.makeExtension(),
            zerver.lib.bugdown.help_settings_links.makeExtension(),
            zerver.lib.bugdown.help_relative_links.makeExtension(),
            zerver.lib.bugdown.help_emoticon_translations_table.makeExtension(
            ),
        ]
    if md_macro_extension is None:
        md_macro_extension = markdown_include.include.makeExtension(
            base_path='templates/zerver/help/include/')

    if any(doc in markdown_file_path for doc in docs_without_macros):
        md_engine = markdown.Markdown(extensions=md_extensions)
    else:
        md_engine = markdown.Markdown(extensions=md_extensions +
                                      [md_macro_extension])
    md_engine.reset()

    jinja = engines['Jinja2']

    try:
        # By default, we do both Jinja2 templating and markdown
        # processing on the file, to make it easy to use both Jinja2
        # context variables and markdown includes in the file.
        markdown_string = jinja.env.loader.get_source(jinja.env,
                                                      markdown_file_path)[0]
    except TemplateNotFound as e:
        if pure_markdown:
            # For files such as /etc/zulip/terms.md where we don't intend
            # to use Jinja2 template variables, we still try to load the
            # template using Jinja2 (in case the file path isn't absolute
            # and does happen to be in Jinja's recognized template
            # directories), and if that fails, we try to load it directly
            # from disk.
            with open(markdown_file_path) as fp:
                markdown_string = fp.read()
        else:
            raise e

    html = md_engine.convert(markdown_string)
    rendered_html = jinja.from_string(html).render(context)

    if context.get('unescape_rendered_html', False):
        # In some exceptional cases (such as our Freshdesk webhook docs),
        # code blocks in some of our Markdown templates have characters such
        # as '{' encoded as '{' to prevent clashes with Jinja2 syntax,
        # but the encoded form never gets decoded because the text ends up
        # inside a <pre> tag. So here, we explicitly "unescape" such characters
        # if 'unescape_rendered_html' is True.
        rendered_html = unescape(rendered_html)

    return mark_safe(rendered_html)
Exemplo n.º 3
0
def render_markdown_path(markdown_file_path: str,
                         context: Optional[Dict[Any, Any]]=None,
                         pure_markdown: Optional[bool]=False) -> str:
    """Given a path to a markdown file, return the rendered html.

    Note that this assumes that any HTML in the markdown file is
    trusted; it is intended to be used for documentation, not user
    data."""

    if context is None:
        context = {}

    # We set this global hackishly
    from zerver.lib.bugdown.help_settings_links import set_relative_settings_links
    set_relative_settings_links(bool(context.get('html_settings_links')))
    from zerver.lib.bugdown.help_relative_links import set_relative_help_links
    set_relative_help_links(bool(context.get('html_settings_links')))

    global md_extensions
    global md_macro_extension
    if md_extensions is None:
        md_extensions = [
            markdown.extensions.extra.makeExtension(),
            markdown.extensions.toc.makeExtension(),
            markdown.extensions.admonition.makeExtension(),
            markdown.extensions.codehilite.makeExtension(
                linenums=False,
                guess_lang=False
            ),
            zerver.lib.bugdown.fenced_code.makeExtension(),
            zerver.lib.bugdown.api_arguments_table_generator.makeExtension(
                base_path='templates/zerver/api/'),
            zerver.lib.bugdown.api_code_examples.makeExtension(),
            zerver.lib.bugdown.nested_code_blocks.makeExtension(),
            zerver.lib.bugdown.tabbed_sections.makeExtension(),
            zerver.lib.bugdown.help_settings_links.makeExtension(),
            zerver.lib.bugdown.help_relative_links.makeExtension(),
            zerver.lib.bugdown.help_emoticon_translations_table.makeExtension(),
        ]
    if md_macro_extension is None:
        md_macro_extension = zerver.lib.bugdown.include.makeExtension(
            base_path='templates/zerver/help/include/')

    if any(doc in markdown_file_path for doc in docs_without_macros):
        md_engine = markdown.Markdown(extensions=md_extensions)
    else:
        md_engine = markdown.Markdown(extensions=md_extensions + [md_macro_extension])
    md_engine.reset()

    jinja = engines['Jinja2']

    try:
        # By default, we do both Jinja2 templating and markdown
        # processing on the file, to make it easy to use both Jinja2
        # context variables and markdown includes in the file.
        markdown_string = jinja.env.loader.get_source(jinja.env, markdown_file_path)[0]
    except TemplateNotFound as e:
        if pure_markdown:
            # For files such as /etc/zulip/terms.md where we don't intend
            # to use Jinja2 template variables, we still try to load the
            # template using Jinja2 (in case the file path isn't absolute
            # and does happen to be in Jinja's recognized template
            # directories), and if that fails, we try to load it directly
            # from disk.
            with open(markdown_file_path) as fp:
                markdown_string = fp.read()
        else:
            raise e

    html = md_engine.convert(markdown_string)
    rendered_html = jinja.from_string(html).render(context)

    if context.get('unescape_rendered_html', False):
        # In some exceptional cases (such as our Freshdesk webhook docs),
        # code blocks in some of our Markdown templates have characters such
        # as '{' encoded as '&#123;' to prevent clashes with Jinja2 syntax,
        # but the encoded form never gets decoded because the text ends up
        # inside a <pre> tag. So here, we explicitly "unescape" such characters
        # if 'unescape_rendered_html' is True.
        rendered_html = unescape(rendered_html)

    return mark_safe(rendered_html)