From 3cca445cad93ea76c1610347146f5b9e3916a04b Mon Sep 17 00:00:00 2001 From: Pablo Revilla Date: Fri, 17 Oct 2025 12:54:44 -0700 Subject: [PATCH] worked on making map and base all API driven --- meshview/templates/base.html | 92 +++-- meshview/templates/map.html | 650 ++++++++++------------------------- meshview/web.py | 171 +++++---- 3 files changed, 349 insertions(+), 564 deletions(-) diff --git a/meshview/templates/base.html b/meshview/templates/base.html index eb741a5..b3a0f5c 100644 --- a/meshview/templates/base.html +++ b/meshview/templates/base.html @@ -1,10 +1,7 @@ - + - - Meshview - {{ site_config.get("site", {}).get("title", "") }} - {% if node and node.short_name %}-- {{ node.short_name }}{% endif %} - + Meshview @@ -29,27 +26,13 @@ - {% set site = site_config.get("site", {}) %} -
-
- {{ site.get("title", "") }} {{ site.get("domain", "") }} -
-
- {{ site.get("message", "") }} -
+ + +
- -
- {% if site.get("nodes") == "True" %}Nodes{% endif %} - {% if site.get("conversations") == "True" %} - Conversations{% endif %} - {% if site.get("everything") == "True" %} - See Everything{% endif %} - {% if site.get("graphs") == "True" %} - Mesh Graphs{% endif %} - {% if site.get("net") == "True" %} - Weekly Net{% endif %} - {% if site.get("map") == "True" %} - Live Map{% endif %} - {% if site.get("stats") == "True" %} - Stats{% endif %} - {% if site.get("top") == "True" %} - Top Traffic Nodes{% endif %} -
+ +
@@ -75,7 +58,7 @@ @@ -85,15 +68,15 @@ {% block body %}{% endblock %}
-
ver. {{ SOFTWARE_RELEASE | default("unknown") }}
+ +
ver. unknown

+ + + diff --git a/meshview/templates/map.html b/meshview/templates/map.html index 9ac65e5..7136734 100644 --- a/meshview/templates/map.html +++ b/meshview/templates/map.html @@ -1,80 +1,33 @@ {% extends "base.html" %} + {% block css %} {% endblock %} {% block body %} -
+
Show Routers Only
-
+
@@ -87,438 +40,191 @@ crossorigin> - {% endblock %} diff --git a/meshview/web.py b/meshview/web.py index 613bdbe..e70194e 100644 --- a/meshview/web.py +++ b/meshview/web.py @@ -1159,16 +1159,6 @@ async def net(request): @routes.get("/map") async def map(request): try: - nodes = await store.get_nodes(days_active=3) - - # Filter out nodes with no latitude - nodes = [node for node in nodes if node.last_lat is not None] - - # Optional datetime formatting - for node in nodes: - if hasattr(node, "last_update") and isinstance(node.last_update, datetime.datetime): - node.last_update = node.last_update.isoformat() - # Parse optional URL parameters for custom view map_center_lat = request.query.get("lat") map_center_lng = request.query.get("lng") @@ -1190,19 +1180,18 @@ async def map(request): return web.Response( text=template.render( - nodes=nodes, - custom_view=custom_view, - site_config=CONFIG, - SOFTWARE_RELEASE=SOFTWARE_RELEASE, + custom_view=custom_view, ), content_type="text/html", ) except Exception as e: - return web.Response( - text="An error occurred while processing your request.", - status=500, - content_type="text/plain", - ) + print(f"/map route error: {e}") + return web.Response( + text="An error occurred while processing your request.", + status=500, + content_type="text/plain", + ) + @routes.get("/stats") @@ -1406,31 +1395,6 @@ async def nodegraph(request): content_type="text/html", ) - -# Show basic details about the site on the site -@routes.get("/config") -async def get_config(request): - try: - site = CONFIG.get("site", {}) - mqtt = CONFIG.get("mqtt", {}) - - return web.json_response( - { - "Server": site.get("domain", ""), - "Title": site.get("title", ""), - "Message": site.get("message", ""), - "MQTT Server": mqtt.get("server", ""), - "Topics": json.loads(mqtt.get("topics", "[]")), - "Release": SOFTWARE_RELEASE, - "Time": datetime.datetime.now().isoformat(), - }, - dumps=lambda obj: json.dumps(obj, indent=2), - ) - - except (json.JSONDecodeError, TypeError): - return web.json_response({"error": "Invalid configuration format"}, status=500) - - # API Section ####################################################################### # How this works @@ -1678,25 +1642,6 @@ async def api_stats(request): return web.json_response(stats) -@routes.get("/api/config") -async def api_config(request): - try: - site = CONFIG.get("site", {}) - safe_site = { - "map_interval": site.get("map_interval", 3), - "firehose_interval": site.get("firehose_interval", 3), - "map_top_left_lat": site.get("map_top_left_lat", 3), - "map_top_left_lon": site.get("map_top_left_lon", 3), - "map_bottom_right_lat": site.get("map_bottom_right_lat", 3), - "map_bottom_right_lon": site.get("map_bottom_right_lon", 3), - } - safe_config = {"site": safe_site} - - return web.json_response(safe_config) - except Exception as e: - return web.json_response({"error": str(e)}, status=500) - - @routes.get("/api/edges") async def api_edges(request): since = datetime.datetime.now() - datetime.timedelta(hours=48) @@ -1739,6 +1684,106 @@ async def api_edges(request): return web.json_response({"edges": edges_list}) +@routes.get("/api/config") +async def api_config(request): + try: + # ------------------ Helpers ------------------ + def get(section, key, default=None): + """Safe getter for both dict and ConfigParser.""" + if isinstance(section, dict): + return section.get(key, default) + return section.get(key, fallback=default) + + def get_bool(section, key, default=False): + val = get(section, key, default) + if isinstance(val, bool): + return "true" if val else "false" + if isinstance(val, str): + return "true" if val.lower() in ("1", "true", "yes", "on") else "false" + return "true" if bool(val) else "false" + + def get_float(section, key, default=0.0): + try: + return float(get(section, key, default)) + except Exception: + return float(default) + + def get_int(section, key, default=0): + try: + return int(get(section, key, default)) + except Exception: + return default + + def get_str(section, key, default=""): + val = get(section, key, default) + return str(val) if val is not None else str(default) + + # ------------------ SITE ------------------ + site = CONFIG.get("site", {}) + safe_site = { + "domain": get_str(site, "domain", ""), + "language": get_str(site, "language", "en"), + "title": get_str(site, "title", ""), + "message": get_str(site, "message", ""), + "starting": get_str(site, "starting", "/chat"), + "nodes": get_bool(site, "nodes", True), + "conversations": get_bool(site, "conversations", True), + "everything": get_bool(site, "everything", True), + "graphs": get_bool(site, "graphs", True), + "stats": get_bool(site, "stats", True), + "net": get_bool(site, "net", True), + "map": get_bool(site, "map", True), + "top": get_bool(site, "top", True), + "map_top_left_lat": get_float(site, "map_top_left_lat", 39.0), + "map_top_left_lon": get_float(site, "map_top_left_lon", -123.0), + "map_bottom_right_lat": get_float(site, "map_bottom_right_lat", 36.0), + "map_bottom_right_lon": get_float(site, "map_bottom_right_lon", -121.0), + "map_interval": get_int(site, "map_interval", 3), + "firehose_interval": get_int(site, "firehose_interval", 3), + "weekly_net_message": get_str(site, "weekly_net_message", "Weekly Mesh check-in message."), + "net_tag": get_str(site, "net_tag", "#BayMeshNet"), + "version": str(SOFTWARE_RELEASE), + } + + # ------------------ MQTT ------------------ + mqtt = CONFIG.get("mqtt", {}) + topics_raw = get(mqtt, "topics", []) + import json + if isinstance(topics_raw, str): + try: + topics = json.loads(topics_raw) + except Exception: + topics = [topics_raw] + elif isinstance(topics_raw, list): + topics = topics_raw + else: + topics = [] + + safe_mqtt = { + "server": get_str(mqtt, "server", ""), + "topics": topics, + } + + # ------------------ CLEANUP ------------------ + cleanup = CONFIG.get("cleanup", {}) + safe_cleanup = { + "enabled": get_bool(cleanup, "enabled", False), + "days_to_keep": get_str(cleanup, "days_to_keep", "14"), + "hour": get_str(cleanup, "hour", "2"), + "minute": get_str(cleanup, "minute", "0"), + "vacuum": get_bool(cleanup, "vacuum", False), + } + + safe_config = { + "site": safe_site, + "mqtt": safe_mqtt, + "cleanup": safe_cleanup, + } + + return web.json_response(safe_config) + except Exception as e: + return web.json_response({"error": str(e)}, status=500) + @routes.get("/api/lang") async def api_lang(request):