http: Add static file support
Static files are configured using a handful of config values. Static files can be handled remotely or locally for prod or dev environments, respectively. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
from typing import Sequence
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
@@ -19,8 +20,16 @@ def required(name: str) -> str:
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def default(name: str, default: str) -> str:
|
def default(name: str, default_value: str) -> str:
|
||||||
return os.getenv(name, default)
|
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"))
|
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"))
|
DB_SQLITE3_PATH = Path(default("DB_SQLITE3_PATH", "bans.db"))
|
||||||
|
|
||||||
HTTP_DOMAIN = required("HTTP_DOMAIN")
|
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")
|
||||||
|
|||||||
@@ -15,14 +15,15 @@ from .db import get_db, search_db
|
|||||||
|
|
||||||
|
|
||||||
def route_url(url: str):
|
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
|
return config.HTTP_ROOT
|
||||||
elif config.HTTP_ROOT in ("/" or ""):
|
|
||||||
return url
|
|
||||||
elif url.startswith("/"):
|
|
||||||
return f"{config.HTTP_ROOT}{url}"
|
|
||||||
else:
|
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(
|
_env = Environment(
|
||||||
@@ -32,6 +33,7 @@ _env = Environment(
|
|||||||
_env.globals.update(
|
_env.globals.update(
|
||||||
{
|
{
|
||||||
"route_url": route_url,
|
"route_url": route_url,
|
||||||
|
"static_url": static_url,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -160,9 +162,20 @@ class IndexView(TemplateView):
|
|||||||
app = web.Application()
|
app = web.Application()
|
||||||
app.add_routes(
|
app.add_routes(
|
||||||
[
|
[
|
||||||
web.get(route_url(r"/"), IndexView),
|
web.get(config.HTTP_ROOT, IndexView),
|
||||||
web.get(route_url(r"/faq"), template_view_factory("faq.html")),
|
web.get(f"{config.HTTP_ROOT}/faq", template_view_factory("faq.html")),
|
||||||
web.get(route_url(r"/news"), template_view_factory("news.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,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
|
/*
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
*/
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -155,6 +157,9 @@ table tr {
|
|||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<nav>
|
||||||
|
[ <a href="{{route_url("/")}}">Home</a> / <a href="{{route_url("/news")}}">News</a> / <a href="{{route_url("/faq")}}">FAQ</a> ]
|
||||||
|
</nav>
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<header>
|
<header>
|
||||||
{% block header %}
|
{% block header %}
|
||||||
@@ -172,9 +177,6 @@ table tr {
|
|||||||
</div>
|
</div>
|
||||||
{% endblock header %}
|
{% endblock header %}
|
||||||
</header>
|
</header>
|
||||||
<nav>
|
|
||||||
[ <a href="{{route_url("/")}}">Home</a> / <a href="{{route_url("/news")}}">News</a> / <a href="{{route_url("/faq")}}">FAQ</a> ]
|
|
||||||
</nav>
|
|
||||||
<main>
|
<main>
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="file-thumb">
|
<span class="file-thumb">
|
||||||
<img src="{{post['thumb_path']}}" data-md5="{{post['md5']}}" loading="lazy">
|
<img src="{{static_url(post['thumb_path'])}}" data-md5="{{post['md5']}}" loading="lazy">
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
25
example.env
25
example.env
@@ -7,9 +7,32 @@
|
|||||||
# Sqlite3 database path. Defaults to "bans.db"
|
# Sqlite3 database path. Defaults to "bans.db"
|
||||||
#DB_SQLITE3_PATH=bans.db
|
#DB_SQLITE3_PATH=bans.db
|
||||||
|
|
||||||
# Domain name of the server
|
# Domain name of the server. This is required.
|
||||||
HTTP_DOMAIN=domain.com
|
HTTP_DOMAIN=domain.com
|
||||||
|
|
||||||
# Root of the HTTP server. Defaults to "/"
|
# Root of the HTTP server. Defaults to "/"
|
||||||
# If you host other things on your domain, you may want to update this to be "/bans" or something.
|
# If you host other things on your domain, you may want to update this to be "/bans" or something.
|
||||||
#HTTP_ROOT=/
|
#HTTP_ROOT=/
|
||||||
|
|
||||||
|
# Static files handler. Defaults to "local"
|
||||||
|
# Valid values are:
|
||||||
|
# * local
|
||||||
|
# * remote
|
||||||
|
# Locally handled static files use the STATIC_LOCAL_PATH config value.
|
||||||
|
# IN GENERAL, the "local" configuration should not be used in a production environment.
|
||||||
|
#STATIC_HANDLER=local
|
||||||
|
|
||||||
|
# The local path to serve static files out of. Defaults to "static"
|
||||||
|
# This is only used when STATIC_HANDLER is set to "local".
|
||||||
|
#STATIC_LOCAL_PATH=static
|
||||||
|
|
||||||
|
# Whether to follow symlinks in the local static file handler. Defaults to "true"
|
||||||
|
# This is only used when STATIC_HANDLER is set to "local".
|
||||||
|
# Must be one of:
|
||||||
|
# * 1, true, yes
|
||||||
|
# * 0, false, no
|
||||||
|
#STATIC_LOCAL_FOLLOW_SYMLINKS=true
|
||||||
|
|
||||||
|
# This is the URL to map static files to. Defaults to /static
|
||||||
|
# This *WILL NOT* prepend the HTTP_ROOT path.
|
||||||
|
#STATIC_ROOT=/static
|
||||||
|
|||||||
Reference in New Issue
Block a user