basis/components/web/__init__.py
apeters 519dbc73c6 Cat.
Signed-off-by: apeters <apeters@korves.net>
2025-06-03 11:40:56 +00:00

145 lines
4.0 KiB
Python

import asyncio
import json
import os
import time
from config import defaults
from components.database import IN_MEMORY_DB
from components.utils import merge_deep, ensure_list
from components.utils.datetimes import ntime_utc_now
from components.web.blueprints import *
from components.web.utils import *
app = Quart(
__name__,
static_url_path="/static",
static_folder="static_files",
template_folder="templates",
)
app.register_blueprint(root.blueprint)
app.register_blueprint(auth.blueprint)
app.register_blueprint(objects.blueprint)
app.register_blueprint(profile.blueprint)
app.register_blueprint(system.blueprint)
app.register_blueprint(users.blueprint)
app.register_blueprint(groups.blueprint)
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = defaults.SEND_FILE_MAX_AGE_DEFAULT
app.config["SECRET_KEY"] = defaults.SECRET_KEY
app.config["TEMPLATES_AUTO_RELOAD"] = defaults.TEMPLATES_AUTO_RELOAD
app.config["SERVER_NAME"] = defaults.HOSTNAME
app.config["MOD_REQ_LIMIT"] = 10
modifying_request_limiter = asyncio.Semaphore(app.config["MOD_REQ_LIMIT"])
@app.context_processor
def load_context():
enforce_dbupdate = IN_MEMORY_DB.get("ENFORCE_DBUPDATE", False)
if enforce_dbupdate:
enforce_dbupdate = defaults.CLUSTER_ENFORCE_DBUPDATE_TIMEOUT - (
round(ntime_utc_now() - enforce_dbupdate)
)
return {
"ENFORCE_DBUPDATE": enforce_dbupdate,
}
@app.errorhandler(ClusterHTTPException)
async def handle_cluster_error(error):
error_msg = str(error.description)
await ws_htmx(
"system",
"beforeend",
"""<div hidden _="on load trigger
notification(
title: 'Cluster error',
level: 'system',
message: '{error}',
duration: 10000
)"></div>""".format(
error=error_msg
),
)
return trigger_notification(
level="error",
response_body="",
response_code=error.code,
title="Cluster error",
message=error_msg,
)
@app.before_request
async def before_request():
request.form_parsed = {}
request.locked = False
if session.get("id") and session["id"] in IN_MEMORY_DB["PROMOTE_USERS"]:
IN_MEMORY_DB["PROMOTE_USERS"].discard(session["id"])
user = await get(user_id=session["id"])
if "system" not in user.acl:
user.acl.append("system")
session["acl"] = user.acl
IN_MEMORY_DB["SESSION_VALIDATED"].update({session["id"]: user.acl})
if request.method in ["POST", "PATCH", "PUT", "DELETE"]:
await modifying_request_limiter.acquire()
form = await request.form
request.form_parsed = dict()
if form:
for k in form:
v = form.getlist(k)
if len(v) == 1:
request.form_parsed = merge_deep(
request.form_parsed, parse_form_to_dict(k, v.pop())
)
else:
request.form_parsed = merge_deep(
request.form_parsed, parse_form_to_dict(k, v)
)
@app.after_request
async def after_request(response):
if defaults.DISABLE_CACHE == False:
return response
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
response.headers["Cache-Control"] = "public, max-age=0"
return response
@app.teardown_request
async def teardown_request(exc):
modifying_request_limiter.release()
@app.context_processor
def load_defaults():
_defaults = {
k: v
for k, v in defaults.__dict__.items()
if not (k.startswith("__") or k.startswith("_"))
}
return _defaults
@app.template_filter(name="hex")
def to_hex(value):
return value.hex()
@app.template_filter(name="ensurelist")
def ensurelist(value):
return ensure_list(value)
@app.template_filter(name="toprettyjson")
def to_prettyjson(value):
return json.dumps(value, sort_keys=True, indent=2, separators=(",", ": "))