Compare commits

...

2 Commits

Author SHA1 Message Date
Christopher Arndt d6e24aa359 feat: support rendering message template with Jinja
Add config setting to enable Jinja templates

Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
2023-07-24 01:07:32 +02:00
Christopher Arndt 92d85d31bf fix: do not require bleach module by default
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
2023-07-23 23:54:03 +02:00
3 changed files with 73 additions and 26 deletions

View File

@ -1,5 +1,5 @@
FROM python:3.11-alpine
RUN python3 -m pip --no-cache-dir install bleach markdown matrix-nio
RUN python3 -m pip --no-cache-dir install bleach jinja2 markdown matrix-nio
ADD matrixchat-notify.py /bin/
ADD matrixchat-notify-config.json /etc/
RUN chmod +x /bin/matrixchat-notify.py

View File

@ -40,7 +40,7 @@ steps:
* `allowed_tags` *(default:* [`DEFAULT_ALLOWED_TAGS`]*)*
List or set or string with comma-separated list of HTML tag names. HTML
tags not included, will be stripped from the HTML output generated by
tags not included will be stripped from the HTML output generated by
rendering a Markdown message template.
Note that the default list does not include any tags, which allow to load
@ -64,11 +64,28 @@ steps:
The Matrix homeserver URL.
* `jinja`
If set to `yes`, `y`, `true`, `t`, `on` or `1`, the message template is
rendered with the [Jinja] templating engine (instead of performing simple
placeholder substitution). The template context is controlled by the
`pass_environment` setting, same as with non-Jinja templates, but
placeholders use a different syntax (example: `{{DRONE_REPO}}`), so the
`template` setting should be changed to be a valid Jinja2 template string
when this is enabled.
Using this feature requires the `jinja2` Python module to be available
(it is installed by default in the plugin's docker image).
* `markdown`
If set to `yes`, `y`, `true` or `on`, the message resulting from template
substtution is considered to be in Markdown format and will be rendered to
HTML and sent as a formatted message with `org.matrix.custom.html` format.
If set to `yes`, `y`, `true`, `t`, `on` or `1`, the message resulting from
template substtution is considered to be in Markdown format and will be
rendered to HTML and sent as a formatted message with the format set to
`org.matrix.custom.html`.
Using this feature requires the `markdown` and `bleach` Python modules to
be available (they are installed by default in the plugin's docker image).
* `markdown_extensions` *(default:* `admonition, extra, sane_lists, smarty`)
@ -95,9 +112,9 @@ steps:
* `template` *(default:* `${DRONE_BUILD_STATUS}`*)*
The message template. Valid placeholders of the form `${PLACEHOLDER}` will
be substituted with the values of the matching environment variables
(subject to filtering according to the `pass_environment` setting).
The message template. Valid placeholders (example: `${DRONE_REPO}`) will be
substituted with the values of the matching environment variables (subject
to filtering according to the `pass_environment` setting).
See this [reference] for environment variables available in drone.io CI
pipelines.
@ -107,10 +124,11 @@ steps:
ID of user on homeserver to send message as (ID, not username).
[`DEFAULT_ALLOWED_ATTRS`]: ./matrixchat-notify.py#L29
[`DEFAULT_ALLOWED_TAGS`]: ./matrixchat-notify.py#L35
[`DEFAULT_ALLOWED_ATTRS`]: ./matrixchat-notify.py#L27
[`DEFAULT_ALLOWED_TAGS`]: ./matrixchat-notify.py#L34
[allowed attributes]: https://bleach.readthedocs.io/en/latest/clean.html#allowed-attributes-attributes
[drone.io]: https://drone.io/
[jinja]: https://jinja.palletsprojects.com/
[list of extensions]: https://python-markdown.github.io/extensions/
[plugin]: https://docs.drone.io/plugins/overview/
[reference]: https://docs.drone.io/pipeline/environment/reference/

View File

@ -5,6 +5,7 @@ Requires:
* <https://pypi.org/project/matrix-nio>
* Optional: <https://pypi.org/project/bleach/>
* Optional: <https://pypi.org/project/Jinja2/>
* Optional: <https://pypi.org/project/markdown/>
"""
@ -20,36 +21,47 @@ from distutils.util import strtobool
from os.path import exists
from string import Template
import bleach
from nio import AsyncClient, LoginResponse
PROG = "matrixchat-notify"
CONFIG_FILENAME = f"{PROG}-config.json"
DEFAULT_ALLOWED_ATTRS = bleach.ALLOWED_ATTRIBUTES.copy()
DEFAULT_ALLOWED_ATTRS.update(
{
DEFAULT_ALLOWED_ATTRS = {
"*": ["class"],
"a": ["href", "title"],
"abbr": ["title"],
"acronym": ["title"],
"img": ["alt", "src"],
}
)
DEFAULT_ALLOWED_TAGS = bleach.ALLOWED_TAGS | {
}
DEFAULT_ALLOWED_TAGS = {
"a",
"abbr",
"acronym",
"b",
"blockquote",
"code",
"dd",
"div",
"dl",
"dt",
"em",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"i",
"li",
"ol",
"p",
"span",
"strong",
"table",
"td",
"th",
"thead",
"tr",
"ul",
}
DEFAULT_HOMESERVER = "https://matrix.org"
DEFAULT_MARKDOWN_EXTENSIONS = "admonition, extra, sane_lists, smarty"
@ -62,6 +74,7 @@ SETTINGS_KEYS = (
"deviceid",
"devicename",
"homeserver",
"jinja",
"markdown",
"markdown_extensions",
"pass_environment",
@ -75,7 +88,7 @@ log = logging.getLogger(PROG)
def tobool(s):
try:
return strtobool(s)
return strtobool(str(s))
except ValueError:
return False
@ -145,15 +158,15 @@ async def send_notification(config, message):
await client.close()
def render_message(config):
pass_environment = config.get("pass_environment", "")
def get_template_context(config):
pass_environment = config.get("pass_environment", [])
if not isinstance(pass_environment, list):
pass_environment = [pass_environment]
patterns = []
for value in pass_environment:
# expand any comma-separetd names/patterns
# expand any comma-separated names/patterns
if "," in value:
patterns.extend([p.strip() for p in value.split(",") if p.strip()])
else:
@ -165,12 +178,28 @@ def render_message(config):
for pattern in patterns:
filtered_names.update(fnmatch.filter(env_names, pattern))
context = {name: os.environ[name] for name in tuple(filtered_names)}
return {name: os.environ[name] for name in tuple(filtered_names)}
def render_message(config):
context = get_template_context(config)
template = config.get("template", DEFAULT_TEMPLATE)
if tobool(config.get("jinja")):
try:
from jinja2.sandbox import SandboxedEnvironment
env = SandboxedEnvironment()
return env.from_string(template).render(context)
except Exception as exc:
log.error("Could not render Jinja2 template: %s", exc)
return template
else:
return Template(template).safe_substitute(context)
def render_markdown(message, config):
import bleach
import markdown
allowed_attrs = config.get("allowed_attrs", DEFAULT_ALLOWED_ATTRS)