|
# Written by retoor@molodetz.nl
|
|
|
|
# This source code implements a web application using the aiohttp framework. It provides a template rendering system that supports both HTML and Markdown files. The `TemplateView` class handles both GET and POST requests, resolving and rendering templates based on request paths. The `Dreamii` class sets up the application environment, adding support for markdown and python extension within jinja2 templates.
|
|
|
|
# Imports:
|
|
# 1. `aiohttp_jinja2`, `web` are part of the aiohttp framework for creating web servers and managing web requests.
|
|
# 2. `MarkdownExtension` and `PythonExtension` are custom extensions that facilitate Markdown and Python rendering within templates.
|
|
|
|
# MIT License
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
|
|
from app.app import Application as BaseApplication, BaseView
|
|
import pathlib
|
|
from aiohttp import web
|
|
from dreamii.markdown import MarkdownExtension, MarkdownRenderer, render_markdown_sync
|
|
from dreamii.python import PythonExtension
|
|
import aiohttp_jinja2
|
|
import html
|
|
|
|
class TemplateView(BaseView):
|
|
|
|
async def resolve_template(self, path):
|
|
path = pathlib.Path(self.request.app.template_path).joinpath(str(path).lstrip('/'))
|
|
if path.exists() and path.suffix in ['.html', '.md']:
|
|
return str(path)
|
|
elif path.joinpath('.md').exists():
|
|
return str(path.joinpath('.md'))
|
|
elif path.joinpath('.html').exists():
|
|
return str(path.joinpath('.html'))
|
|
elif path.is_dir():
|
|
if path.joinpath('index.html').exists():
|
|
return str(path.joinpath('index.html'))
|
|
elif path.joinpath('index.md').exists():
|
|
return str(path.joinpath('index.md'))
|
|
return None
|
|
|
|
async def render_template(self, path):
|
|
context = {}
|
|
context['request'] = self.request
|
|
context['post'] = await self.request.post()
|
|
context["template"] = pathlib.Path(path)
|
|
if not context['post']:
|
|
context['post'] = None
|
|
try:
|
|
context['json'] = await self.request.json()
|
|
except:
|
|
context['json'] = None
|
|
pass
|
|
self.request.app.jinja2_env.globals["request"] = self.request
|
|
self.request.app.jinja2_env.globals["context"] = context
|
|
self.request.app.jinja2_env.globals["template"] = template
|
|
|
|
if str(path).endswith(".md"):
|
|
renderer = MarkdownRenderer(self.request.app, path)
|
|
|
|
|
|
|
|
|
|
content = pathlib.Path(path).read_text()
|
|
if pathlib.Path(self.template_path).joinpath("_base.html").exists():
|
|
markdown_default_page = "{% extends \"_base.html\" %}<html>{% block content %}<style>{{ highlight_styles }}</style>{% markdown %}"+content+"{% endmarkdown %}{% endblock %}</body></html>"
|
|
else:
|
|
markdown_default_page = "\n".join([
|
|
"<html>",
|
|
"<head>",
|
|
"<meta charset=\"utf-8\">",
|
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
|
|
"<title>" + html.escape(path.split("/")[-1].rstrip(".md")) +"</title>",
|
|
"<style>{{ highlight_styles }}</style>",
|
|
"</head>",
|
|
"<body>{% markdown %}"+content+"{% endmarkdown %}</body>",
|
|
"</html>"
|
|
])
|
|
with open(".temp.html", "w+") as f:
|
|
f.write(markdown_default_page)
|
|
content = aiohttp_jinja2.render_string(".temp.html",self.request,context=context)
|
|
pathlib.Path(".temp.html").unlink()
|
|
response = web.Response(text=content, content_type="text/html")
|
|
return response
|
|
|
|
return await super().render_template(path)
|
|
|
|
|
|
async def get(self):
|
|
path = await self.resolve_template(self.request.match_info['tail'])
|
|
if path:
|
|
print("Found path", path)
|
|
return await self.render_template(path)
|
|
path = pathlib.Path(self.request.app.template_path).joinpath(self.request.match_info['tail'].lstrip('/'))
|
|
if path.exists():
|
|
print("Found non template path", path)
|
|
return web.Response(body=path.read_bytes())
|
|
print("Path not found", path)
|
|
return web.Response(status=404)
|
|
|
|
async def post(self):
|
|
path = await self.resolve_template(self.request.match_info['tail'])
|
|
if path:
|
|
return await self.render_template(path)
|
|
path = pathlib.Path(self.request.app.template_path).joinpath(self.request.match_info['tail'].lstrip('/'))
|
|
if path.exists():
|
|
return web.Response(body=path.read_bytes())
|
|
return web.Response(status=404)
|
|
|
|
class Dreamii(BaseApplication):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(template_path=".", *args, **kwargs)
|
|
self.router.add_view("/{tail:.*}", TemplateView)
|
|
self.jinja2_env.enable_async = False
|
|
self.jinja2_env.globals["app"] = self
|
|
self.jinja2_env.globals["request"] = None
|
|
self.jinja2_env.globals["context"] = {}
|
|
self.jinja2_env.add_extension(MarkdownExtension)
|
|
self.jinja2_env.add_extension(PythonExtension)
|
|
|
|
def run(self, port=7331):
|
|
web.run_app(self, port=port)
|
|
|
|
if __name__ == '__main__':
|
|
app = Dreamii()
|
|
app.run()
|