import logging from typing import Any import tornado 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 from core.enums import Continent, Mode, ModeType from core.utils import safe_json_dumps from data.activities import ACTIVITIES logger = logging.getLogger(__name__) class APIOptionsHandler(tornado.web.RequestHandler): """API request handler for /api/v2/options""" def __init__( self, application: "Application", request: httputil.HTTPServerRequest, **kwargs: Any, ): self._status_data = None self._spot_providers = None super().__init__(application, request, **kwargs) def initialize(self, status_data, spot_providers=None): self._status_data = status_data self._spot_providers = spot_providers or [] def get(self): try: # 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 activity in ACTIVITIES.values(): # 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. spot_providers: list = [ p["name"] for p in filter(lambda p: p["enabled"], self._status_data["spot_providers"]) ] alert_providers = [p["name"] for p in filter(lambda p: p["enabled"], self._status_data["alert_providers"])] callsign_data_providers = [ p["name"] for p in filter( lambda p: p["enabled"], self._status_data["callsign_data_providers"], ) ] spot_providers_enabled_by_default = [ p["name"] for p in filter( lambda p: p["enabled"] and p["enabled_by_default_in_web_ui"], self._status_data["spot_providers"], ) ] # If spotting to this server is enabled, "API" is another valid spot source even though it does not come from # one of our providers. if ALLOW_SPOTTING: spot_providers.append("API") spot_providers_enabled_by_default.append("API") options = { "bands": BANDS, "modes": [m.value for m in Mode], "mode_types": [t.value for t in ModeType], "sigs": list(ACTIVITIES.values()), "spot_providers": spot_providers, "spot_providers_enabled_by_default": spot_providers_enabled_by_default, "alert_providers": alert_providers, "callsign_data_providers": callsign_data_providers, "continents": [c.value for c in Continent], "propagation_modes": list(PROPAGATION_MODES.values()), "max_spot_age": MAX_SPOT_AGE, "spot_allowed": ALLOW_SPOTTING, "spot_submit_providers": spot_submit_providers, } self.write(safe_json_dumps(options)) self.set_status(200) self.set_header("Cache-Control", "no-store") self.set_header("Content-Type", "application/json") except Exception: logger.exception("Exception when handling client request to options API") self.write(safe_json_dumps("Error - an internal server error occurred.")) self.set_status(500)