Giant refactor to rebrand "SIG" as "Activity" anywhere that doesn't touch API or config file (which is to be addressed in a future breaking change). #147

This commit is contained in:
Ian Renton
2026-09-18 14:54:11 +01:00
parent 556ea56378
commit 81cd686a00
96 changed files with 1208 additions and 1170 deletions
+9 -9
View File
@@ -8,9 +8,9 @@ import tornado
from tornado import httputil
from tornado.web import Application
from core.activity_utils import get_ref_regex_for_activity
from core.config import ALLOW_SPOTTING, ALLOW_UPSTREAM_SPOTTING, RECAPTCHA_SECRET_KEY
from core.constants import UNKNOWN_BAND
from core.sig_utils import get_ref_regex_for_sig
from core.utils import infer_band_from_freq, safe_json_dumps
from data.spot import Spot
from providers.spot.spot_provider import SpotProvider
@@ -142,14 +142,14 @@ class APISpotHandler(tornado.web.RequestHandler):
self.set_header("Content-Type", "application/json")
return
# Reject if sig_ref format incorrect for sig
# Reject if activity ref format incorrect for activity
if (
spot.sig
and spot.sig_refs
and len(spot.sig_refs) > 0
and spot.sig_refs[0].id
and get_ref_regex_for_sig(spot.sig)
and not re.match(get_ref_regex_for_sig(spot.sig), spot.sig_refs[0].id)
and get_ref_regex_for_activity(spot.sig)
and not re.match(get_ref_regex_for_activity(spot.sig), spot.sig_refs[0].id)
):
self.set_status(422)
self.write(
@@ -173,13 +173,13 @@ class APISpotHandler(tornado.web.RequestHandler):
if submit_upstream and upstream_provider_name:
if not spot.sig:
self.set_status(422)
self.write(safe_json_dumps("Error - a SIG must be selected to submit upstream."))
self.write(safe_json_dumps("Error - an activity must be selected to submit upstream."))
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(safe_json_dumps("Error - a SIG reference is required to submit upstream."))
self.write(safe_json_dumps("Error - an activity reference is required to submit upstream."))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
@@ -241,11 +241,11 @@ class APISpotHandler(tornado.web.RequestHandler):
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
def _find_provider(self, provider_name, sig) -> SpotProvider | None:
"""Find an enabled provider by name that can submit spots for the given SIG."""
def _find_provider(self, provider_name, activity) -> SpotProvider | None:
"""Find an enabled provider by name that can submit spots for the given activity."""
for p in self._spot_providers:
if p.enabled and p.name == provider_name and p.can_submit_spot(sig):
if p.enabled and p.name == provider_name and p.can_submit_spot(activity):
return p
return None
+6 -6
View File
@@ -187,13 +187,13 @@ def alert_allowed_by_query(alert, query):
if not alert.source or alert.source not in sources:
return False
case "sig":
# If a list of sigs is provided, the alert must have a sig and it must match one of them.
# The special "sig" "NO_SIG", when supplied in the list, mathches alerts with no sig.
sigs = query.get(k).split(",")
include_no_sig = "NO_SIG" in sigs
if not alert.sig and not include_no_sig:
# If a list of activities is provided, the alert must have an activity and it must match one of them.
# The special activity "NO_SIG", when supplied in the list, matches alerts with no activity.
activities = query.get(k).split(",")
include_no_activity = "NO_SIG" in activities
if not alert.sig and not include_no_activity:
return False
if alert.sig and alert.sig not in sigs:
if alert.sig and alert.sig not in activities:
return False
case "dx_continent":
dxconts = query.get(k).split(",")
+18 -14
View File
@@ -6,18 +6,18 @@ import tornado
from tornado import httputil
from tornado.web import Application
from core.activity_lookup_helper import populate_missing_activity_ref_info
from core.activity_utils import get_ref_regex_for_activity
from core.call_lookup_helper import get_call_info
from core.constants import SIGS
from core.constants import ACTIVITIES
from core.geo_utils import (
lat_lon_for_grid_sw_corner_plus_size,
lat_lon_to_cq_zone,
lat_lon_to_itu_zone,
)
from core.sig_lookup_helper import populate_missing_sig_ref_info
from core.sig_utils import get_ref_regex_for_sig
from core.utils import safe_json_dumps
from data.activity_ref import ActivityRef
from data.lookup_credentials import extract_credentials
from data.sig_ref import SIGRef
logger = logging.getLogger(__name__)
@@ -63,7 +63,7 @@ class APILookupCallHandler(tornado.web.RequestHandler):
self.set_header("Content-Type", "application/json")
class APILookupSIGRefHandler(tornado.web.RequestHandler):
class APILookupActivityRefHandler(tornado.web.RequestHandler):
"""API request handler for /api/v2/lookup/sigref"""
def __init__(
@@ -80,30 +80,34 @@ class APILookupSIGRefHandler(tornado.web.RequestHandler):
# reduce that to just the first entry, and convert bytes to string
query_params = {k: v[0].decode("utf-8") for k, v in self.request.arguments.items()}
# "sig" and "id" query params must exist, SIG must be known, and if we have a reference regex for that SIG,
# the provided id must match it.
# "sig" and "id" query params must exist, the activity must be known, and if we have a reference regex for
# that activity, the provided id must match it.
if "sig" in query_params and "id" in query_params:
sig = str(query_params.get("sig")).upper()
activity = str(query_params.get("sig")).upper()
ref_id = str(query_params.get("id")).upper()
if sig in [p.name.upper() for p in SIGS]:
if not get_ref_regex_for_sig(sig) or re.match(get_ref_regex_for_sig(sig), ref_id):
data = populate_missing_sig_ref_info(SIGRef(id=ref_id, sig=sig))
if activity in [a.name.upper() for a in ACTIVITIES]:
if not get_ref_regex_for_activity(activity) or re.match(
get_ref_regex_for_activity(activity), ref_id
):
data = populate_missing_activity_ref_info(ActivityRef(id=ref_id, sig=activity))
self.write(safe_json_dumps(data))
else:
self.write(
safe_json_dumps(f"Error - '{ref_id}' does not look like a valid reference ID for {sig}.")
safe_json_dumps(
f"Error - '{ref_id}' does not look like a valid reference ID for {activity}."
)
)
self.set_status(422)
else:
self.write(safe_json_dumps(f"Error - sig '{sig}' is not known."))
self.write(safe_json_dumps(f"Error - sig '{activity}' is not known."))
self.set_status(422)
else:
self.write(safe_json_dumps("Error - sig and id must be provided"))
self.set_status(422)
except Exception:
logger.exception("Exception when handling client request to sig ref lookup API")
logger.exception("Exception when handling client request to activity ref lookup API")
self.write(safe_json_dumps("Error - an internal server error occurred."))
self.set_status(500)
+6 -6
View File
@@ -6,7 +6,7 @@ from tornado import httputil
from tornado.web import Application
from core.config import ALLOW_SPOTTING, MAX_SPOT_AGE
from core.constants import BANDS, PROPAGATION_MODES, SIGS
from core.constants import ACTIVITIES, BANDS, PROPAGATION_MODES
from core.enums import Continent, Mode, ModeType
from core.utils import safe_json_dumps
@@ -32,16 +32,16 @@ class APIOptionsHandler(tornado.web.RequestHandler):
def get(self):
try:
# Build a map of SIG name -> list of provider names that can submit spots for that SIG
# Build a map of activity name -> list of provider names that can submit spots for that activity
spot_submit_providers = {}
# Spothole v2.0 - disable this for now, API changes are in but this functionality is not ready yet. TODO
# for provider in self._spot_providers:
# if not provider.enabled:
# continue
# for sig in SIGS:
# if provider.can_submit_spot(sig.name):
# spot_submit_providers.setdefault(sig.name, []).append(provider.name)
# for activity in ACTIVITIES:
# if provider.can_submit_spot(activity.name):
# spot_submit_providers.setdefault(activity.name, []).append(provider.name)
# Spot/alert sources are filtered for only ones that are enabled in config, no point letting the user toggle
# things that aren't even available.
@@ -74,7 +74,7 @@ class APIOptionsHandler(tornado.web.RequestHandler):
"bands": BANDS,
"modes": [m.value for m in Mode],
"mode_types": [t.value for t in ModeType],
"sigs": SIGS,
"sigs": ACTIVITIES,
"spot_providers": spot_providers,
"spot_providers_enabled_by_default": spot_providers_enabled_by_default,
"alert_providers": alert_providers,
+12 -12
View File
@@ -197,24 +197,24 @@ def spot_allowed_by_query(spot, query):
if not spot.source or spot.source not in sources:
return False
case "sig":
# If a list of sigs is provided, the spot must have a sig and it must match one of them.
# The special "sig" "NO_SIG", when supplied in the list, mathches spots with no sig.
sigs = query.get(k).split(",")
include_no_sig = "NO_SIG" in sigs
if not spot.sig and not include_no_sig:
# If a list of activities is provided, the spot must have an activity and it must match one of them.
# The special activity "NO_SIG", when supplied in the list, matches spots with no activity.
activities = query.get(k).split(",")
include_no_activity = "NO_SIG" in activities
if not spot.sig and not include_no_activity:
return False
if spot.sig and spot.sig not in sigs:
if spot.sig and spot.sig not in activities:
return False
case "needs_sig":
# If true, a sig is required, regardless of what it is, it just can't be missing. Mutually
# If true, an activity is required, regardless of what it is, it just can't be missing. Mutually
# exclusive with supplying the special "NO_SIG" parameter to the "sig" query param.
needs_sig = query.get(k).upper() == "TRUE"
if needs_sig and not spot.sig:
needs_activity = query.get(k).upper() == "TRUE"
if needs_activity and not spot.sig:
return False
case "needs_sig_ref":
# If true, at least one sig ref is required, regardless of what it is, it just can't be missing.
needs_sig_ref = query.get(k).upper() == "TRUE"
if needs_sig_ref and (not spot.sig_refs or len(spot.sig_refs) == 0):
# If true, at least one activity ref is required, regardless of what it is, it just can't be missing.
needs_activity_ref = query.get(k).upper() == "TRUE"
if needs_activity_ref and (not spot.sig_refs or len(spot.sig_refs) == 0):
return False
case "band":
bands = query.get(k).split(",")
+4 -4
View File
@@ -6,9 +6,9 @@ import tornado
from tornado import httputil
from tornado.web import Application
from core.activity_utils import get_ref_regex_for_activity
from core.config import ALLOW_SPOTTING
from core.constants import UNKNOWN_BAND
from core.sig_utils import get_ref_regex_for_sig
from core.utils import infer_band_from_freq, safe_json_dumps
from data.spot import Spot
@@ -104,14 +104,14 @@ class V1APISpotHandler(tornado.web.RequestHandler):
self.set_header("Content-Type", "application/json")
return
# Reject if sig_ref format incorrect for sig
# Reject if activity ref format incorrect for activity
if (
spot.sig
and spot.sig_refs
and len(spot.sig_refs) > 0
and spot.sig_refs[0].id
and get_ref_regex_for_sig(spot.sig)
and not re.match(get_ref_regex_for_sig(spot.sig), spot.sig_refs[0].id)
and get_ref_regex_for_activity(spot.sig)
and not re.match(get_ref_regex_for_activity(spot.sig), spot.sig_refs[0].id)
):
self.set_status(422)
self.write(