diff --git a/.gitignore b/.gitignore index 7c8d358..4d2926c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ __pycache__ avatar.png build/ dist/ +index.html.j2 pip-wheel-metadata/ testbot.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c2bb2..71f94b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # xbotlib x.x.x (UNRELEASED) +# xbotlib 0.12.2 (2021-01-17) + +- Support loading Jinja2 template ([#30](https://git.autonomic.zone/decentral1se/xbotlib/issues/30)) + # xbotlib 0.12.1 (2021-01-17) - Allow to configure port diff --git a/README.md b/README.md index e59a7e2..655f397 100644 --- a/README.md +++ b/README.md @@ -105,13 +105,6 @@ Arguments: - **request**: the web request -```python -from xbotlib import Response - -def serve(self, request): - return Response(text="Hello, World!") -``` - ### SimpleMessage A simple message interface. @@ -213,7 +206,8 @@ optional arguments: --no-auto-join Disable automatically joining rooms when invited -pt PORT, --port PORT The port to serve from - + -t TEMPLATE, --template TEMPLATE + The template to render ``` #### Using the environment @@ -276,13 +270,18 @@ Your bot will automatically be running a web server at port `8080` when it is run. If you're running your bot locally, just visit [0.0.0.0:8080](http://0.0.0.0:8080) to see. The default response is just some placeholder text. You can write your own responses using the -[Bot.serve](#botserve) function. +[Bot.serve](#bot-serve-request) function. `xbotlib` provides a small wrapper API for [Jinja2](https://jinja.palletsprojects.com/en/2.11.x/) which allows you to easily template and generate HTML. The web server is provided by [aiohttp](https://docs.aiohttp.org/). +The default template search path is `index.html.j2` in the current working +directory. This can be configured through the usual configuration entrypoints. + +Here's a small example. + ```python from xbotlib import Response diff --git a/pyproject.toml b/pyproject.toml index 25c11aa..c4abbfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.masonry.api" [tool.poetry] name = "xbotlib" -version = "0.12.1" +version = "0.12.2" description = "XMPP bots for humans" authors = ["decentral1se "] maintainers = ["decentral1se "] diff --git a/xbotlib.py b/xbotlib.py index 51a07a1..0aa292b 100644 --- a/xbotlib.py +++ b/xbotlib.py @@ -8,13 +8,14 @@ from getpass import getpass from imghdr import what from inspect import cleandoc from logging import DEBUG, INFO, basicConfig, getLogger -from os import environ +from os import environ, getcwd from os.path import exists from pathlib import Path from sys import exit, stdout from aiohttp.web import Application, Response, get, run_app from humanize import naturaldelta +from jinja2 import Environment, FileSystemLoader from redis import Redis from slixmpp import ClientXMPP @@ -139,6 +140,11 @@ class Config: """The port to serve from.""" return self.section.get("port", None) + @property + def template(self): + """The Jinja template to render.""" + return self.section.get("template", None) + class Bot(ClientXMPP): """XMPP bots for humans.""" @@ -150,7 +156,6 @@ class Bot(ClientXMPP): """Initialise the object.""" self.name = type(self).__name__.lower() self.start = dt.now() - self.CONFIG_FILE = f"{self.name}.conf" self.parse_arguments() @@ -222,6 +227,12 @@ class Bot(ClientXMPP): dest="port", help="The port to serve from", ) + self.parser.add_argument( + "-t", + "--template", + dest="template", + help="The template to render", + ) self.args = self.parser.parse_args() @@ -303,6 +314,13 @@ class Bot(ClientXMPP): ) port = input("Port: ") + print( + "Please choose Jinja template file path", + "(leave empty to choose default value of index.html.j2)", + sep="\n", + ) + template = input("Jinja HTML template: ") + print("*" * 79) config = ConfigParser() @@ -322,6 +340,8 @@ class Bot(ClientXMPP): ) if port: config[self.name]["port"] = port + if template: + config[self.name]["template"] = template with open(self.CONFIG_FILE, "w") as file_handle: config.write(file_handle) @@ -369,6 +389,12 @@ class Bot(ClientXMPP): or environ.get("XBOT_PORT", None) or "8080" ) + template = ( + self.args.template + or self.config.template + or environ.get("XBOT_TEMPLATE", None) + or "index.html.j2" + ) if not account: self.log.error("Unable to discover account") @@ -390,6 +416,19 @@ class Bot(ClientXMPP): self.rooms = rooms self.no_auto_join = no_auto_join self.port = port + self.template = self.load_template(template) + + def load_template(self, template): + """Load template via Jinja.""" + if not exists(Path(template).absolute()): + return None + + try: + loader = FileSystemLoader(searchpath="./") + env = Environment(loader=loader) + return env.get_template(template) + except Exception: + self.log.info(f"Unable to load {template}") def register_xmpp_event_handlers(self): """Register functions against specific XMPP event handlers."""