POSTing a spot should use the request body not a URL param. #35

This commit is contained in:
Ian Renton
2025-10-09 15:29:25 +01:00
parent 1843286f92
commit c66693fc99
3 changed files with 45 additions and 19 deletions

View File

@@ -5,7 +5,7 @@ from threading import Thread
import bottle
import pytz
from bottle import run, response, template
from bottle import run, request, response, template
from core.config import MAX_SPOT_AGE, ALLOW_SPOTTING
from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, CONTINENTS
@@ -74,14 +74,21 @@ class WebServer:
return json.dumps("Error - this server does not allow new spots to be added via the API.",
default=serialize_everything)
# Reject if no spot
if not bottle.request.query.spot:
# Reject if format not json
if not request.get_header('Content-Type') or request.get_header('Content-Type') != "application/json":
response.content_type = 'application/json'
response.status = 415
return json.dumps("Error - request Content-Type must be application/json", default=serialize_everything)
# Reject if request body is empty
post_data = request.body.read()
if not post_data:
response.content_type = 'application/json'
response.status = 422
return json.dumps("Error - no 'spot' parameter provided", default=serialize_everything)
return json.dumps("Error - request body is empty", default=serialize_everything)
# Read in the spot as JSON then convert to a Spot object
json_spot = json.loads(bottle.request.query.spot)
# Read in the request body as JSON then convert to a Spot object
json_spot = json.loads(post_data)
spot = Spot(**json_spot)
# Reject if no timestamp or dx_call
@@ -96,6 +103,7 @@ class WebServer:
spot.icon = "desktop"
spot.infer_missing()
self.spots.add(spot.id, spot, expire=MAX_SPOT_AGE)
print(spot)
response.content_type = 'application/json'
response.set_header('Cache-Control', 'no-store')
@@ -103,7 +111,7 @@ class WebServer:
except Exception as e:
logging.error(e)
response.content_type = 'application/json'
response.status = 422
response.status = 500
return json.dumps("Error - " + str(e), default=serialize_everything)
# Serve a templated page
@@ -220,7 +228,7 @@ class WebServer:
# The idea is that this will include most of the things that can be provided as queries to the main spots call,
# and thus a client can use this data to configure its filter controls.
def get_options(self):
return {"bands": BANDS,
options = {"bands": BANDS,
"modes": ALL_MODES,
"mode_types": MODE_TYPES,
"sigs": SIGS,
@@ -231,3 +239,9 @@ class WebServer:
map(lambda p: p["name"], filter(lambda p: p["enabled"], self.status_data["alert_providers"]))),
"continents": CONTINENTS,
"max_spot_age": MAX_SPOT_AGE}
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
# one of our proviers.
if ALLOW_SPOTTING:
options["spot_sources"].append("API")
return options