mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-29 02:32:05 +00:00
Replace pages' use of the options call with directly building the HTML components using templates, as the syntax is much nicer. Use a common set of data provided to all modules via pagetemplate.py instead of passing things like web_ui_options around. Closes #153
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import functools
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -7,6 +8,7 @@ from tornado.web import Application
|
||||
|
||||
from core.config import ALLOW_SPOTTING, MAX_SPOT_AGE
|
||||
from core.constants import BANDS, PROPAGATION_MODES
|
||||
from core.data_providers import DATA_PROVIDERS
|
||||
from core.enums import Continent, Mode, ModeType
|
||||
from core.utils import safe_json_dumps
|
||||
from data.activities import ACTIVITIES
|
||||
@@ -14,6 +16,54 @@ from data.activities import ACTIVITIES
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@functools.cache
|
||||
def build_options():
|
||||
"""Build the options data that is returned by the /options API and used to populate the web UI templates. This
|
||||
doesn't change at runtime, so it is built once on first use and then cached."""
|
||||
|
||||
# Build a map of activity name -> list of provider names that can submit spots for that activity
|
||||
spot_submit_providers = {}
|
||||
|
||||
# Spothole v2.0 - disable this for now, API changes are in but this functionality is not ready yet. TODO
|
||||
# for provider in DATA_PROVIDERS.spot_providers:
|
||||
# if not provider.enabled:
|
||||
# continue
|
||||
# for activity in ACTIVITIES.values():
|
||||
# if provider.can_submit_spot(activity.name):
|
||||
# spot_submit_providers.setdefault(activity.name, []).append(provider.name)
|
||||
|
||||
# Spot/alert sources are filtered for only ones that are enabled in config, no point letting the user toggle
|
||||
# things that aren't even available.
|
||||
spot_providers = [p.name for p in DATA_PROVIDERS.spot_providers if p.enabled]
|
||||
alert_providers = [p.name for p in DATA_PROVIDERS.alert_providers if p.enabled]
|
||||
callsign_data_providers = [p.name for p in DATA_PROVIDERS.callsign_data_providers if p.enabled]
|
||||
spot_providers_enabled_by_default = [
|
||||
p.name for p in DATA_PROVIDERS.spot_providers if p.enabled and p.enabled_by_default_in_web_ui
|
||||
]
|
||||
|
||||
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
|
||||
# one of our providers.
|
||||
if ALLOW_SPOTTING:
|
||||
spot_providers.append("API")
|
||||
spot_providers_enabled_by_default.append("API")
|
||||
|
||||
return {
|
||||
"bands": BANDS,
|
||||
"modes": [m.value for m in Mode],
|
||||
"mode_types": [t.value for t in ModeType],
|
||||
"activities": list(ACTIVITIES.values()),
|
||||
"spot_providers": spot_providers,
|
||||
"spot_providers_enabled_by_default": spot_providers_enabled_by_default,
|
||||
"alert_providers": alert_providers,
|
||||
"callsign_data_providers": callsign_data_providers,
|
||||
"continents": [c.value for c in Continent],
|
||||
"propagation_modes": list(PROPAGATION_MODES.values()),
|
||||
"max_spot_age": MAX_SPOT_AGE,
|
||||
"spot_allowed": ALLOW_SPOTTING,
|
||||
"spot_submit_providers": spot_submit_providers,
|
||||
}
|
||||
|
||||
|
||||
class APIOptionsHandler(tornado.web.RequestHandler):
|
||||
"""API request handler for /api/v3/options"""
|
||||
|
||||
@@ -23,73 +73,13 @@ class APIOptionsHandler(tornado.web.RequestHandler):
|
||||
request: httputil.HTTPServerRequest,
|
||||
**kwargs: Any,
|
||||
):
|
||||
self._status_data = None
|
||||
self._spot_providers = None
|
||||
super().__init__(application, request, **kwargs)
|
||||
|
||||
def initialize(self, status_data, spot_providers=None):
|
||||
self._status_data = status_data
|
||||
self._spot_providers = spot_providers or []
|
||||
|
||||
def get(self):
|
||||
try:
|
||||
# Build a map of activity name -> list of provider names that can submit spots for that activity
|
||||
spot_submit_providers = {}
|
||||
|
||||
# Spothole v2.0 - disable this for now, API changes are in but this functionality is not ready yet. TODO
|
||||
# for provider in self._spot_providers:
|
||||
# if not provider.enabled:
|
||||
# continue
|
||||
# for activity in ACTIVITIES.values():
|
||||
# if provider.can_submit_spot(activity.name):
|
||||
# spot_submit_providers.setdefault(activity.name, []).append(provider.name)
|
||||
|
||||
# Spot/alert sources are filtered for only ones that are enabled in config, no point letting the user toggle
|
||||
# things that aren't even available.
|
||||
spot_providers: list = [
|
||||
p["name"] for p in filter(lambda p: p["enabled"], self._status_data["spot_providers"])
|
||||
]
|
||||
alert_providers = [p["name"] for p in filter(lambda p: p["enabled"], self._status_data["alert_providers"])]
|
||||
callsign_data_providers = [
|
||||
p["name"]
|
||||
for p in filter(
|
||||
lambda p: p["enabled"],
|
||||
self._status_data["callsign_data_providers"],
|
||||
)
|
||||
]
|
||||
spot_providers_enabled_by_default = [
|
||||
p["name"]
|
||||
for p in filter(
|
||||
lambda p: p["enabled"] and p["enabled_by_default_in_web_ui"],
|
||||
self._status_data["spot_providers"],
|
||||
)
|
||||
]
|
||||
|
||||
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
|
||||
# one of our providers.
|
||||
if ALLOW_SPOTTING:
|
||||
spot_providers.append("API")
|
||||
spot_providers_enabled_by_default.append("API")
|
||||
|
||||
options = {
|
||||
"bands": BANDS,
|
||||
"modes": [m.value for m in Mode],
|
||||
"mode_types": [t.value for t in ModeType],
|
||||
"activities": list(ACTIVITIES.values()),
|
||||
"spot_providers": spot_providers,
|
||||
"spot_providers_enabled_by_default": spot_providers_enabled_by_default,
|
||||
"alert_providers": alert_providers,
|
||||
"callsign_data_providers": callsign_data_providers,
|
||||
"continents": [c.value for c in Continent],
|
||||
"propagation_modes": list(PROPAGATION_MODES.values()),
|
||||
"max_spot_age": MAX_SPOT_AGE,
|
||||
"spot_allowed": ALLOW_SPOTTING,
|
||||
"spot_submit_providers": spot_submit_providers,
|
||||
}
|
||||
|
||||
self.write(safe_json_dumps(options))
|
||||
self.write(safe_json_dumps(build_options()))
|
||||
self.set_status(200)
|
||||
self.set_header("Cache-Control", "no-store")
|
||||
self.set_header("Cache-Control", "max-age=3600")
|
||||
self.set_header("Content-Type", "application/json")
|
||||
|
||||
except Exception:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
import tornado
|
||||
@@ -5,7 +6,6 @@ from tornado import httputil
|
||||
from tornado.web import Application
|
||||
|
||||
from core.config import (
|
||||
ALLOW_SPOTTING,
|
||||
BASE_URL,
|
||||
SERVER_OWNER_CALLSIGN,
|
||||
TELNET_SERVER_ADDRESS,
|
||||
@@ -14,6 +14,14 @@ from core.config import (
|
||||
WEB_UI_OPTIONS,
|
||||
)
|
||||
from core.constants import SOFTWARE_VERSION
|
||||
from core.utils import infer_mode_type_from_mode, safe_json_dumps
|
||||
from webserver.handlers.api.options import build_options
|
||||
|
||||
|
||||
def dom_safe_name(name):
|
||||
"""Strip characters from a name that are not allowed in HTML element IDs"""
|
||||
|
||||
return re.sub(r"^[^A-Za-z0-9]+|\W+", "", name, flags=re.ASCII)
|
||||
|
||||
|
||||
class PageTemplateHandler(tornado.web.RequestHandler):
|
||||
@@ -31,17 +39,27 @@ class PageTemplateHandler(tornado.web.RequestHandler):
|
||||
def initialize(self, template_name):
|
||||
self._template_name = template_name
|
||||
|
||||
def get(self):
|
||||
# Load named template, and provide variables used in templates
|
||||
self.render(
|
||||
f"{self._template_name}.html",
|
||||
def get_template_namespace(self):
|
||||
"""Provide variables and helper functions to all page templates"""
|
||||
|
||||
namespace = super().get_template_namespace()
|
||||
namespace.update(
|
||||
# Various options
|
||||
options=build_options(),
|
||||
web_ui_options=WEB_UI_OPTIONS,
|
||||
# Other single static parameters
|
||||
software_version=SOFTWARE_VERSION,
|
||||
server_owner_callsign=SERVER_OWNER_CALLSIGN,
|
||||
allow_spotting=ALLOW_SPOTTING,
|
||||
web_ui_options=WEB_UI_OPTIONS,
|
||||
baseurl=BASE_URL,
|
||||
telnet_server_enabled=TELNET_SERVER_ENABLED,
|
||||
telnet_server_address=TELNET_SERVER_ADDRESS,
|
||||
telnet_server_port=TELNET_SERVER_PORT,
|
||||
current_path=self.request.path,
|
||||
# Function references that templates need
|
||||
dom_safe_name=dom_safe_name,
|
||||
safe_json_dumps=safe_json_dumps,
|
||||
infer_mode_type_from_mode=infer_mode_type_from_mode,
|
||||
)
|
||||
return namespace
|
||||
|
||||
def get(self):
|
||||
self.render(f"{self._template_name}.html")
|
||||
|
||||
Reference in New Issue
Block a user