Implement templating to avoid copy/paste HTML code. #7

This commit is contained in:
Ian Renton
2025-10-02 11:16:38 +01:00
parent 10f8d9b4ed
commit cc1a7a9b8c
17 changed files with 105 additions and 117 deletions

View File

@@ -5,7 +5,7 @@ from threading import Thread
import bottle
import pytz
from bottle import run, response
from bottle import run, response, template
from core.config import MAX_SPOT_AGE
from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, SOURCES, CONTINENTS
@@ -26,11 +26,15 @@ class WebServer:
self.thread.daemon = True
self.status = "Starting"
# Set up routing
bottle.get("/api/spots")(self.serve_api_spots)
bottle.get("/api/options")(self.serve_api_options)
bottle.get("/api/status")(self.serve_api_status)
bottle.get("/")(self.serve_index)
# Routes for API calls
bottle.get("/api/spots")(lambda: self.serve_api(self.get_spot_list_with_filters()))
bottle.get("/api/options")(lambda: self.serve_api(self.get_options()))
bottle.get("/api/status")(lambda: self.serve_api(self.status_data))
# Routes for templated pages
bottle.get("/")(lambda: self.serve_template('webpage_home'))
bottle.get("/about")(lambda: self.serve_template('webpage_about'))
bottle.get("/apidocs")(lambda: self.serve_template('webpage_apidocs'))
# Default route to serve from "webassets"
bottle.get("/<filepath:path>")(self.serve_static_file)
# Start the web server
@@ -43,51 +47,29 @@ class WebServer:
self.status = "Waiting"
run(host='localhost', port=self.port)
# Main spots API
def serve_api_spots(self):
# Serve a JSON API endpoint
def serve_api(self, data):
self.last_api_access_time = datetime.now(pytz.UTC)
self.status = "OK"
spots_json = json.dumps(self.get_spot_list_with_filters(bottle.request.query), default=serialize_everything)
response.content_type = 'application/json'
return spots_json
return json.dumps(data, default=serialize_everything)
# Options API
def serve_api_options(self):
self.last_api_access_time = datetime.now(pytz.UTC)
self.status = "OK"
status_json = json.dumps(self.get_options(), default=serialize_everything)
response.content_type = 'application/json'
return status_json
# Server status API
def serve_api_status(self):
self.last_api_access_time = datetime.now(pytz.UTC)
self.status = "OK"
status_json = json.dumps(self.status_data, default=serialize_everything)
response.content_type = 'application/json'
return status_json
# Serve the home page. This would be accessible as /index.html but we need this workaround to make it available as /
def serve_index(self):
return self.serve_static_file("")
# Serve general static files from "webassets" directory, along with some extra workarounds to make URLs such as
# "/", "/about" and "/apidocs" work.
def serve_static_file(self, filepath):
# Serve a templated page
def serve_template(self, template_name):
self.last_page_access_time = datetime.now(pytz.UTC)
self.status = "OK"
if filepath == "":
return bottle.static_file("index.html", root="webassets")
elif filepath == "about":
return bottle.static_file("about.html", root="webassets")
elif filepath == "apidocs":
return bottle.static_file("index.html", root="webassets/apidocs")
else:
return bottle.static_file(filepath, root="webassets")
return template(template_name)
# Serve general static files from "webassets" directory.
def serve_static_file(self, filepath):
return bottle.static_file(filepath, root="webassets")
# Utility method to apply filters to the overall spot list and return only a subset. Enables query parameters in
# the main "spots" GET call. The "query" parameter should be the result of bottle's request.query, and is a MultiDict
def get_spot_list_with_filters(self, query):
# the main "spots" GET call.
def get_spot_list_with_filters(self):
# Get the query (and the right one, with Bottle magic. This is a MultiDict object
query = bottle.request.query
# Create a shallow copy of the spot list, ordered by spot time. We'll then filter it accordingly.
# We can filter by spot time and received time with "since" and "received_since", which take a UNIX timestamp
# in seconds UTC.