From 8d09484425480f1ea38e6733b09e398a287ff6d8 Mon Sep 17 00:00:00 2001 From: Ian Renton Date: Sat, 20 Jun 2026 10:30:24 +0100 Subject: [PATCH] Move some of the "add spot" checks from client-side to server-side to avoid duplication and enforce them in the proper place. #95 --- server/handlers/api/addspot.py | 33 ++++++++++++++++- templates/add_spot.html | 10 +++--- webassets/js/add-spot.js | 66 +++++----------------------------- 3 files changed, 46 insertions(+), 63 deletions(-) diff --git a/server/handlers/api/addspot.py b/server/handlers/api/addspot.py index f939607..79ec8d5 100644 --- a/server/handlers/api/addspot.py +++ b/server/handlers/api/addspot.py @@ -180,9 +180,40 @@ class APISpotHandler(tornado.web.RequestHandler): self.set_header("Content-Type", "application/json") return + # Validate upstream submission requirements + if submit_upstream and upstream_provider_name: + if not spot.sig: + self.set_status(422) + self.write(json.dumps("Error - a SIG must be selected to submit upstream.", + default=serialize_everything)) + self.set_header("Cache-Control", "no-store") + self.set_header("Content-Type", "application/json") + return + if not spot.sig_refs and upstream_provider_name != "Tiles": + self.set_status(422) + self.write(json.dumps("Error - a SIG reference is required to submit upstream.", + default=serialize_everything)) + self.set_header("Cache-Control", "no-store") + self.set_header("Content-Type", "application/json") + return + if not spot.dx_grid and upstream_provider_name == "Tiles": + self.set_status(422) + self.write(json.dumps("Error - a grid reference is required to submit upstream to Tiles on the Air.", + default=serialize_everything)) + self.set_header("Cache-Control", "no-store") + self.set_header("Content-Type", "application/json") + return + if not spot.mode and upstream_provider_name == "Tiles": + self.set_status(422) + self.write(json.dumps("Error - a mode is required to submit upstream to Tiles on the Air.", + default=serialize_everything)) + self.set_header("Cache-Control", "no-store") + self.set_header("Content-Type", "application/json") + return + # Submit upstream if requested upstream_warning = None - if submit_upstream and upstream_provider_name and spot.sig: + if submit_upstream and upstream_provider_name: provider = self._find_provider(upstream_provider_name, spot.sig) if provider: try: diff --git a/templates/add_spot.html b/templates/add_spot.html index 80b1c80..9d2f007 100644 --- a/templates/add_spot.html +++ b/templates/add_spot.html @@ -24,14 +24,14 @@
-
+
- +
- +
@@ -60,10 +60,10 @@
+ placeholder="N0CALL" required>
- +
diff --git a/webassets/js/add-spot.js b/webassets/js/add-spot.js index 847afaa..5741d5f 100644 --- a/webassets/js/add-spot.js +++ b/webassets/js/add-spot.js @@ -205,40 +205,14 @@ function addSpot() { // Prepare the spot object for the server const spot = {}; - if (dx !== "") { - spot["dx_call"] = dx; - } else { - // todo maybe for neatness just make all these error/rejections server side rather than having logic in two places - showAddSpotError("A DX callsign is required in order to spot."); - return; - } - if (freqStr !== "") { - spot["freq"] = parseFloat(freqStr) * 1000; - } else { - showAddSpotError("A frequency is required in order to spot."); - return; - } - if (mode !== "") { - spot["mode"] = mode; - } - if (sig !== "") { - spot["sig"] = sig; - } - if (sigRef !== "") { - spot["sig_refs"] = [{id: sigRef}]; - } - if (dxGrid !== "") { - spot["dx_grid"] = dxGrid; - } - if (comment !== "") { - spot["comment"] = comment; - } - if (de !== "") { - spot["de_call"] = de; - } else { - showAddSpotError("A spotter callsign is required in order to spot."); - return; - } + spot["dx_call"] = dx; + spot["freq"] = parseFloat(freqStr) * 1000; + if (mode !== "") spot["mode"] = mode; + if (sig !== "") spot["sig"] = sig; + if (sigRef !== "") spot["sig_refs"] = [{id: sigRef}]; + if (dxGrid !== "") spot["dx_grid"] = dxGrid; + if (comment !== "") spot["comment"] = comment; + spot["de_call"] = de; spot["time"] = moment.utc().valueOf() / 1000.0; // Prepare "handling" structure to tell the server what to do with this spot @@ -246,35 +220,13 @@ function addSpot() { // Add CAPTCHA token if reCAPTCHA is loaded if (window._recaptchaWidgetId !== undefined) { - const token = grecaptcha.getResponse(window._recaptchaWidgetId); - if (!token) { - showAddSpotError("Please complete the CAPTCHA to submit upstream."); - return; - } - handling["captcha_token"] = token; + handling["captcha_token"] = grecaptcha.getResponse(window._recaptchaWidgetId); } // Upstream submission const submitUpstream = $("#submit-upstream").is(":checked"); const upstreamProviderName = getSelectedUpstreamProvider(); if (submitUpstream && upstreamProviderName) { - if (!sig) { - showAddSpotError("A SIG must be selected to submit upstream."); - return; - } - if (!sigRef && upstreamProviderName !== "Tiles") { - showAddSpotError("A SIG reference is required to submit upstream."); - return; - } - if (!dxGrid && upstreamProviderName === "Tiles") { - showAddSpotError("A grid reference is required to submit upstream to Tiles on the Air."); - return; - } - if (!mode && upstreamProviderName === "Tiles") { - showAddSpotError("A mode is required to submit upstream to Tiles on the Air."); - return; - } - handling["submit_upstream"] = true; handling["upstream_provider"] = upstreamProviderName; handling["upstream_credentials"] = loadCredentials(upstreamProviderName);