Replace dash-separated config & API properties with underscore-separated versions. #127

This commit is contained in:
Ian Renton
2026-08-10 20:55:18 +01:00
parent 5c86346074
commit c687202a61
54 changed files with 247 additions and 246 deletions
+5 -4
View File
@@ -19,13 +19,14 @@ info:
* **Breaking change:** The "add spot" API has changed to enable future support for upstream submission to the spotting services associated with various SIGs. Instead of just posting the spot object itself as the JSON content of the POST, this has moved into a `spot` object within the structure. A new `handling` object alongside it contains the `submit_upstream`, `upstream_provider`, `upstream_credentials`, and `captcha_token` fields which control the server handling of the spot.
* **Breaking change:** Removed `cleanup` from `/status` response
* **Breaking change:** in the `/options` response, renamed `spot_sources` and `alert_sources` to `spot_providers` and `alert_providers`
* **Breaking change:** In the `/options` response, renamed `spot_sources` and `alert_sources` to `spot_providers` and `alert_providers`
* **Breaking change:** A user's QRZ.com and HamQTH credentials are now supplied as request headers (`X-QRZ-Username`, `X-QRZ-Password`, `X-QRZ-Session-Key`, `X-HamQTH-Username`, `X-HamQTH-Password`, `X-HamQTH-Session-ID`) rather than query parameters, to keep credentials out of server logs.
* **Breaking change:** "WAB/WAI GRID" as a location source has been renamed to just "GRID", and also applies to Tiles on the Air spots and grid references from cluster spot comments.
* **Breaking change:** In the `/status` response, `software-version` has changed to `software_version` and `server-owner-callsign` to `server_owner_callsign`.
* POST `/spot` now supports Google reCaptcha and (if the site owner has set it up) now requires `captcha_token` in order to successfully submit. (This is used to lock down the submit function and prevent submission via Spothole by bots or third-party clients.)
* GET `/options` now returns `spot_submit_providers`, a map of SIG names to the names of providers that support upstream spot submission for that SIG. (This allows clients to present the user with options of where a new spot can be sent to.)
* Added `sig_ref_data_providers`, `static_data_providers` and `callsign_data_providers` to `/status` response
* Added `callsign_data_providers` to `/options` response
* Added `callsign_data_providers` and `spot_providers_enabled_by_default` to `/options` response
#### Upgrading a client from v1 to v2 API endpoints
@@ -1926,11 +1927,11 @@ components:
ServerStatus:
type: object
properties:
"software-version":
"software_version":
type: string
description: The version number of the software.
example: "1.0.1"
"server-owner-callsign":
"server_owner_callsign":
type: string
description: The callsign of this server's operator.
example: "M0TRT"
+3 -3
View File
@@ -27,7 +27,7 @@ function buildQueryString() {
str = str + getQueryStringFor(fn) + "&";
}
});
str = str + "limit=" + $("#alerts-to-fetch option:selected").val();
str = str + "limit=" + $("#alerts_to_fetch option:selected").val();
const maxDur = $("#max-duration option:selected").val();
if (maxDur !== "9999999999") {
str = str + "&max_duration=" + maxDur;
@@ -284,7 +284,7 @@ function loadOptions() {
options = jsonData;
// Populate the filters panel
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#dx_continent_options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#source-options", "source", options["alert_providers"]);
// Load URL params. These may select things from the various filter & display options, so the function needs
@@ -294,7 +294,7 @@ function loadOptions() {
// Load filters from settings storage
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setColorScheme($("#color_scheme option:selected").val());
// Load alerts and set up the timer
loadAlerts();
+7 -7
View File
@@ -61,7 +61,7 @@ function startSSEConnection() {
// Remove spots from the display that are older than the selected max age.
function expireOldSpots() {
const maxAgeSeconds = parseInt($("#max-spot-age option:selected").val());
const maxAgeSeconds = parseInt($("#max_spot_age option:selected").val());
const cutoff = (Date.now() / 1000) - maxAgeSeconds;
const before = spots.length;
spots = spots.filter(s => s["time"] && s["time"] >= cutoff);
@@ -79,7 +79,7 @@ function buildQueryString() {
str = str + getQueryStringFor(fn) + "&";
}
});
str = str + "max_age=" + $("#max-spot-age option:selected").val();
str = str + "max_age=" + $("#max_spot_age option:selected").val();
// Additional filters for the bands view: No dupes, no QRT
str = str + "&dedupe=true&allow_qrt=false";
return str;
@@ -280,8 +280,8 @@ function loadOptions() {
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setBandColorScheme($("#band-color-scheme option:selected").val());
setColorScheme($("#color_scheme option:selected").val());
setBandColorScheme($("#band_color_scheme option:selected").val());
// Add CSS for band toggle buttons
addBandToggleColourCSS(options["bands"]);
@@ -289,10 +289,10 @@ function loadOptions() {
// Populate the filters panel
generateBandsMultiToggleFilterCard(options["bands"]);
generateSIGsMultiToggleFilterCard(options["sigs"]);
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateMultiToggleFilterCard("#dx_continent_options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de_continent_options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_providers"], options["spot-providers-enabled-by-default"]);
generateSourcesMultiToggleFilterCard(options["spot_providers"], options["spot_providers_enabled_by_default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress
+13 -13
View File
@@ -61,11 +61,11 @@ function loadURLParams() {
}
// Handle other params
updateSelectFromParam(params, "color-scheme", "color-scheme");
updateSelectFromParam(params, "time-zone", "time-zone"); // Only on Spots and Alerts pages
updateSelectFromParam(params, "limit", "spots-to-fetch"); // Only on Spots page
updateSelectFromParam(params, "limit", "alerts-to-fetch"); // Only on Alerts page
updateSelectFromParam(params, "max_age", "max-spot-age"); // Only on Map & Bands pages
updateSelectFromParam(params, "color_scheme", "color_scheme");
updateSelectFromParam(params, "time_zone", "time_zone"); // Only on Spots and Alerts pages
updateSelectFromParam(params, "limit", "spots_to_fetch"); // Only on Spots page
updateSelectFromParam(params, "limit", "alerts_to_fetch"); // Only on Alerts page
updateSelectFromParam(params, "max_age", "max_spot_age"); // Only on Map & Bands pages
updateFilterFromParam(params, "band", "band");
updateFilterFromParam(params, "sig", "sig");
updateFilterFromParam(params, "source", "source");
@@ -80,7 +80,7 @@ function updateSelectFromParam(params, paramName, selectID) {
if (v != null) {
$("#" + selectID).prop("value", v);
// Extra check if this is the "color scheme" select
if (selectID === "color-scheme") {
if (selectID === "color_scheme") {
setColorScheme(v);
}
}
@@ -157,7 +157,7 @@ function columnsUpdated() {
// Function to set the colour scheme based on the state of the UI select box
function setColorSchemeFromUI() {
let theme = $("#color-scheme option:selected").val();
let theme = $("#color_scheme option:selected").val();
if (theme !== "") {
setColorScheme(theme);
saveSettings();
@@ -168,7 +168,7 @@ function setColorSchemeFromUI() {
function setColorScheme(mode) {
let effectiveModeDark = mode === "dark";
if (mode === "auto") {
effectiveModeDark = window.matchMedia('(prefers-color-scheme: dark)').matches
effectiveModeDark = window.matchMedia('(prefers-color_scheme: dark)').matches
}
$("html").attr("data-bs-theme", effectiveModeDark ? "dark" : "light");
const metaThemeColor = document.querySelector("meta[name=theme-color]");
@@ -182,7 +182,7 @@ function usePreferredTheme() {
// Work out if we have ever explicitly saved the value of our select box. If so, we set our colour scheme now based
// on that. If not, we let the select stay with nothing selected, so that the server sets it to whatever the
// server's default is when the options call is retrieved.
let val = localStorage.getItem("#color-scheme:value");
let val = localStorage.getItem("#color_scheme:value");
if (val != null) {
setColorScheme(JSON.parse(val));
}
@@ -191,8 +191,8 @@ function usePreferredTheme() {
// Sets up a listener on the OS light-dark theme change. If the Spothole user theme is set to Auto, the UI will be
// updated, otherwise if the Spothole user theme is forced to light or dark, that preference will remain.
function listenForOSThemeChange() {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
setColorScheme($("#color-scheme option:selected").val());
window.matchMedia('(prefers-color_scheme: dark)').addEventListener('change', () => {
setColorScheme($("#color_scheme option:selected").val());
});
}
@@ -254,13 +254,13 @@ function closeDataPanel() {
// provided the corresponding "enabled" checkbox is ticked.
function getCredentialHeaders() {
const headers = {};
if ($("#qrz-enabled")[0] && $("#qrz-enabled")[0].checked) {
if ($("#qrz_enabled")[0] && $("#qrz_enabled")[0].checked) {
const qrzUsername = $("#qrz-username").val();
const qrzPassword = $("#qrz-password").val();
if (qrzUsername) headers["X-QRZ-Username"] = qrzUsername;
if (qrzPassword) headers["X-QRZ-Password"] = qrzPassword;
}
if ($("#hamqth-enabled")[0] && $("#hamqth-enabled")[0].checked) {
if ($("#hamqth_enabled")[0] && $("#hamqth_enabled")[0].checked) {
const hamqthUsername = $("#hamqth-username").val();
const hamqthPassword = $("#hamqth-password").val();
if (hamqthUsername) headers["X-HamQTH-Username"] = hamqthUsername;
+1 -1
View File
@@ -624,7 +624,7 @@ function renderDxStats() {
if (!dxStatsData) {
return;
}
const deContinent = $('#dxstats-de-continent').val();
const deContinent = $('#sxstats_de_continent').val();
const deData = dxStatsData[deContinent];
if (!deData) {
return;
+7 -7
View File
@@ -108,7 +108,7 @@ function startSSEConnection() {
// Remove spots from the map that are older than the selected max age.
function expireOldSpots() {
const maxAgeSeconds = parseInt($("#max-spot-age option:selected").val());
const maxAgeSeconds = parseInt($("#max_spot_age option:selected").val());
const cutoff = (Date.now() / 1000) - maxAgeSeconds;
spots = spots.filter(function (s) {
if (s["time"] && s["time"] < cutoff) {
@@ -170,7 +170,7 @@ function buildQueryString() {
str = str + getQueryStringFor(fn) + "&";
}
});
str = str + "max_age=" + $("#max-spot-age option:selected").val();
str = str + "max_age=" + $("#max_spot_age option:selected").val();
// Additional filters for the map view: No dupes, no QRT, only spots with good locations
str = str + "&dedupe=true&allow_qrt=false";
return str;
@@ -307,8 +307,8 @@ function loadOptions() {
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setBandColorScheme($("#band-color-scheme option:selected").val());
setColorScheme($("#color_scheme option:selected").val());
setBandColorScheme($("#band_color_scheme option:selected").val());
// Add CSS for band toggle buttons
addBandToggleColourCSS(options["bands"]);
@@ -316,10 +316,10 @@ function loadOptions() {
// Populate the filters panel
generateBandsMultiToggleFilterCard(options["bands"]);
generateSIGsMultiToggleFilterCard(options["sigs"]);
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateMultiToggleFilterCard("#dx_continent_options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de_continent_options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_providers"], options["spot-providers-enabled-by-default"]);
generateSourcesMultiToggleFilterCard(options["spot_providers"], options["spot_providers_enabled_by_default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress
+7 -7
View File
@@ -55,7 +55,7 @@ function startSSEConnection() {
// Add spot to internal data store
spots.unshift(newSpot);
// Work out if we need to remove an old spot
if (spots.length > $("#spots-to-fetch option:selected").val()) {
if (spots.length > $("#spots_to_fetch option:selected").val()) {
spots = spots.slice(0, -1);
// Drop oldest spot off the end of the table. This is two rows because of the mobile view extra rows
$("#table tbody tr").last().remove();
@@ -93,7 +93,7 @@ function buildQueryString() {
str = str + getQueryStringFor(fn) + "&";
}
});
str = str + "limit=" + $("#spots-to-fetch option:selected").val();
str = str + "limit=" + $("#spots_to_fetch option:selected").val();
if ($("#search").val() !== "") {
str = str + "&text_includes=" + encodeURIComponent($("#search").val());
}
@@ -421,8 +421,8 @@ function loadOptions() {
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings();
setColorScheme($("#color-scheme option:selected").val());
setBandColorScheme($("#band-color-scheme option:selected").val());
setColorScheme($("#color_scheme option:selected").val());
setBandColorScheme($("#band_color_scheme option:selected").val());
// Add CSS for band toggle buttons
addBandToggleColourCSS(options["bands"]);
@@ -430,10 +430,10 @@ function loadOptions() {
// Populate the filters panel
generateBandsMultiToggleFilterCard(options["bands"]);
generateSIGsMultiToggleFilterCard(options["sigs"]);
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateMultiToggleFilterCard("#dx_continent_options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de_continent_options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_providers"], options["spot-providers-enabled-by-default"]);
generateSourcesMultiToggleFilterCard(options["spot_providers"], options["spot_providers_enabled_by_default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress
+1 -1
View File
@@ -102,7 +102,7 @@ function filtersUpdated() {
// Function to update the band colour scheme in spots, bands and map pages
function setBandColorSchemeFromUI() {
setBandColorScheme($("#band-color-scheme option:selected").val());
setBandColorScheme($("#band_color_scheme option:selected").val());
saveSettings();
// Fudge a full reload because we need to update not just colours in the list/map/bands but also the filters
window.location.reload();
+7 -7
View File
@@ -1,8 +1,8 @@
// Load server status
function loadStatus() {
$.getJSON('/api/v2/status', function (jsonData) {
$("#software-version").text(jsonData["software-version"]);
$("#server-owner-callsign").text(jsonData["server-owner-callsign"]);
$("#software_version").text(jsonData["software_version"]);
$("#server_owner_callsign").text(jsonData["server_owner_callsign"]);
$("#up-since").text(moment().subtract(jsonData["uptime"], 'seconds').fromNow());
$("#memory-use").text(jsonData["mem_use_mb"] + " MB");
$("#total-spots").text(jsonData["num_spots"]);
@@ -13,7 +13,7 @@ function loadStatus() {
$("#web-server-last-page").text(moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow());
jsonData["spot_providers"].forEach(p => {
$("#spot-providers-status-container").append(`
$("#spot_providers-status-container").append(`
<div class="row row-cols-1 row-cols-md-4 g-4 mb-4 mb-md-2">
<div class="col"><strong>${p["name"]}</strong></div>
<div class="col">Status: ${p["status"]}</div>
@@ -23,7 +23,7 @@ function loadStatus() {
});
jsonData["alert_providers"].forEach(p => {
$("#alert-providers-status-container").append(`
$("#alert_providers-status-container").append(`
<div class="row row-cols-1 row-cols-md-4 g-4 mb-4 mb-md-2">
<div class="col"><strong>${p["name"]}</strong></div>
<div class="col">Status: ${p["status"]}</div>
@@ -41,7 +41,7 @@ function loadStatus() {
});
jsonData["static_data_providers"].forEach(p => {
$("#static-data-providers-status-container").append(`
$("#static_data_providers-status-container").append(`
<div class="row row-cols-1 row-cols-md-4 g-4 mb-4 mb-md-2">
<div class="col"><strong>${p["name"]}</strong></div>
<div class="col">Status: ${p["status"]}</div>
@@ -50,7 +50,7 @@ function loadStatus() {
});
jsonData["sig_ref_data_providers"].forEach(p => {
$("#sig-ref-data-providers-status-container").append(`
$("#sig_ref_data_providers-status-container").append(`
<div class="row row-cols-1 row-cols-md-4 g-4 mb-4 mb-md-2">
<div class="col"><strong>${p["sig_name"]}</strong></div>
<div class="col">Status: ${p["status"]}</div>
@@ -60,7 +60,7 @@ function loadStatus() {
});
jsonData["callsign_data_providers"].forEach(p => {
$("#callsign-data-providers-status-container").append(`
$("#callsign_data_providers-status-container").append(`
<div class="row row-cols-1 row-cols-md-4 g-4 mb-4 mb-md-2">
<div class="col"><strong>${p["name"]}</strong></div>
<div class="col">Status: ${p["status"]}</div>