150 lines
4.2 KiB
Python
150 lines
4.2 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.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
|
|
IN_MEMORY_DB["SESSION_VALIDATED"] = dict()
|
|
IN_MEMORY_DB["WS_CONNECTIONS"] = dict()
|
|
IN_MEMORY_DB["FORM_OPTIONS_CACHE"] = dict()
|
|
IN_MEMORY_DB["OBJECTS_CACHE"] = dict()
|
|
IN_MEMORY_DB["APP_LOGS_FULL_PULL"] = dict()
|
|
IN_MEMORY_DB["PROMOTE_USERS"] = set()
|
|
|
|
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=(",", ": "))
|