diff --git a/chanbans/config.py b/chanbans/config.py index 7a12755..122f418 100644 --- a/chanbans/config.py +++ b/chanbans/config.py @@ -1,5 +1,6 @@ from pathlib import Path import os +from typing import Sequence from dotenv import load_dotenv @@ -19,8 +20,16 @@ def required(name: str) -> str: return value -def default(name: str, default: str) -> str: - return os.getenv(name, default) +def default(name: str, default_value: str) -> str: + return os.getenv(name, default_value) + + +def one_of_default(name: str, values: Sequence[str], default_value: str) -> str: + value = default(name, default_value) + if value not in values: + required = ",".join(f'"{v}"' for v in values) + raise ConfigError(name, f"must be one of {required}; got {value} instead") + return value THUMBS_DIR = Path(default("THUMBS_DIR", "thumbs")) @@ -29,4 +38,11 @@ CACHE_DIR = Path(default("CACHE_DIR", "cache")) DB_SQLITE3_PATH = Path(default("DB_SQLITE3_PATH", "bans.db")) HTTP_DOMAIN = required("HTTP_DOMAIN") -HTTP_ROOT = default("HTTP_ROOT", r"/") +HTTP_ROOT = default("HTTP_ROOT", r"") + +STATIC_HANDLER = one_of_default("STATIC_HANDLER", ("remote", "local"), "local") +STATIC_LOCAL_PATH = Path(default("STATIC_LOCAL_PATH", "static")) +STATIC_LOCAL_FOLLOW_SYMLINKS = one_of_default( + "STATIC_LOCAL_FOLLOW_SYMLINKS", ("yes", "true", "1", "no", "false", "0"), "true" +) in ("yes", "true", "1") +STATIC_ROOT = default("STATIC_ROOT", "/static") diff --git a/chanbans/http.py b/chanbans/http.py index 38805a6..ba8b235 100644 --- a/chanbans/http.py +++ b/chanbans/http.py @@ -15,14 +15,15 @@ from .db import get_db, search_db def route_url(url: str): - if url in ("/" or ""): + assert url == "" or url[0] == "/", "URL must be blank or start with a slash" + if url in ("", "/"): return config.HTTP_ROOT - elif config.HTTP_ROOT in ("/" or ""): - return url - elif url.startswith("/"): - return f"{config.HTTP_ROOT}{url}" else: - return f"{config.HTTP_ROOT}/{url}" + return f"{config.HTTP_ROOT}{url}" + + +def static_url(resource: str): + return f"{config.STATIC_ROOT}/{resource}" _env = Environment( @@ -32,6 +33,7 @@ _env = Environment( _env.globals.update( { "route_url": route_url, + "static_url": static_url, } ) @@ -160,12 +162,23 @@ class IndexView(TemplateView): app = web.Application() app.add_routes( [ - web.get(route_url(r"/"), IndexView), - web.get(route_url(r"/faq"), template_view_factory("faq.html")), - web.get(route_url(r"/news"), template_view_factory("news.html")), + web.get(config.HTTP_ROOT, IndexView), + web.get(f"{config.HTTP_ROOT}/faq", template_view_factory("faq.html")), + web.get(f"{config.HTTP_ROOT}/news", template_view_factory("news.html")), ] ) +if config.STATIC_HANDLER == "local": + app.add_routes( + [ + web.static( + config.STATIC_ROOT, + config.STATIC_LOCAL_PATH, + follow_symlinks=config.STATIC_LOCAL_FOLLOW_SYMLINKS, + ) + ] + ) + def run_app(): web.run_app(app) diff --git a/chanbans/templates/base.html b/chanbans/templates/base.html index c115d2c..2168df3 100644 --- a/chanbans/templates/base.html +++ b/chanbans/templates/base.html @@ -22,8 +22,10 @@ body { } nav { + /* position: fixed; top: 0; + */ width: 100%; margin: 5px 0; text-align: left; @@ -155,6 +157,9 @@ table tr { {% endblock style %}
+ {% block body %}