diff --git a/server/webserver.py b/server/webserver.py index ceb35f7..46d315c 100644 --- a/server/webserver.py +++ b/server/webserver.py @@ -2,6 +2,7 @@ import json import logging from datetime import datetime, timedelta from threading import Thread +from types import SimpleNamespace import bottle import pytz @@ -10,6 +11,7 @@ from bottle import run, response, template from core.config import MAX_SPOT_AGE from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, CONTINENTS from core.utils import serialize_everything +from data.spot import Spot # Provides the public-facing web server. @@ -61,11 +63,34 @@ class WebServer: self.last_api_access_time = datetime.now(pytz.UTC) self.status = "OK" - print(bottle.request.forms.spot) + try: + # Reject if no spot + if not bottle.request.query.spot: + response.content_type = 'application/json' + response.status = 422 + return json.dumps("Error - no 'spot' parameter provided", default=serialize_everything) - response.content_type = 'application/json' - response.set_header('Cache-Control', 'no-store') - return json.dumps("OK", default=serialize_everything) + # Read in the spot as JSON then convert to a Spot object + json_spot = json.loads(bottle.request.query.spot) + spot = Spot(**json_spot) + + # Reject if no timestamp or dx_call + if not spot.time or not spot.dx_call: + response.content_type = 'application/json' + response.status = 422 + return json.dumps("Error - 'time' and 'dx_call' must be provided as a minimum.", default=serialize_everything) + + # infer missing data, and add it to our database. + spot.infer_missing() + self.spots.add(spot.guid, spot, expire=MAX_SPOT_AGE) + + response.content_type = 'application/json' + response.set_header('Cache-Control', 'no-store') + return json.dumps("OK", default=serialize_everything) + except Exception: + response.content_type = 'application/json' + response.status = 422 + return json.dumps("An error occurred parsing your spot. Check it is compliant with the API.", default=serialize_everything) # Serve a templated page def serve_template(self, template_name): diff --git a/views/webpage_about.tpl b/views/webpage_about.tpl index 74061d5..d0692b6 100644 --- a/views/webpage_about.tpl +++ b/views/webpage_about.tpl @@ -5,7 +5,7 @@
Spothole is a utility to aggregate "spots" from amateur radio DX clusters and xOTA spotting sites, and provide an open JSON API as well as a website to browse the data.
While there are several other web-based interfaces to DX clusters, and sites that aggregate spots from various outdoor activity programmes for amateur radio, Spothole differentiates itself by supporting a large number of data sources, and by being "API first" rather than just providing a web front-end. This allows other software to be built on top of it.
The API is deliberately well-defined with an OpenAPI specification and auto-generated API documentation. The API delivers spots in a consistent format regardless of the data source, freeing developers from needing to know how each individual data source presents its data.
-Spothole itself is also open source, Public Domain licenced code that anyone can take and modify. The source code is here. If you want to run your own copy of Spothole, or start modifying it for your own purposes, the README file there has all the details.
+Spothole itself is also open source, Public Domain licenced code that anyone can take and modify. The source code is here. If you want to run your own copy of Spothole, or start modifying it for your own purposes, the README file contains a description of how the software works and how it's laid out, as well as instructions for configuring systemd, nginx and anything else you might need to run your own server.
Supported data sources include DX Clusters, the Reverse Beacon Network (RBN), the APRS Internet Service (APRS-IS), POTA, SOTA, WWFF, GMA, WWBOTA, HEMA, and Parks 'n' Peaks.
The software was written by Ian Renton, MØTRT.