Allow fetch bm for all repeaters, untag bm if not existing
This commit is contained in:
parent
c1ce81456d
commit
c088cf2cd8
3 changed files with 122 additions and 42 deletions
37
admin.go
37
admin.go
|
|
@ -197,6 +197,7 @@ func handleAdminSaveBMData(db *sql.DB) http.HandlerFunc {
|
||||||
Agl int `json:"agl"`
|
Agl int `json:"agl"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
LastKnownMaster int `json:"last_known_master"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||||
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
|
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
|
||||||
|
|
@ -228,6 +229,42 @@ func handleAdminSaveBMData(db *sql.DB) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add Brandmeister tag if valid master server
|
||||||
|
if payload.LastKnownMaster != 0 && payload.LastKnownMaster != 9999 {
|
||||||
|
db.Exec(`UPDATE repeaters SET networks = array_append(networks, 'Brandmeister')
|
||||||
|
WHERE id = $1 AND NOT networks @> ARRAY['Brandmeister']`, payload.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"ok":true}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleAdminRemoveBMTag(db *sql.DB) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPut {
|
||||||
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||||
|
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if payload.ID <= 0 {
|
||||||
|
http.Error(w, `{"error":"missing id"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`UPDATE repeaters SET networks = array_remove(networks, 'Brandmeister'), last_polled=NOW() WHERE id = $1`, payload.ID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, `{"error":"update failed"}`, http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(`{"ok":true}`))
|
w.Write([]byte(`{"ok":true}`))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
main.go
1
main.go
|
|
@ -46,6 +46,7 @@ func main() {
|
||||||
adminAPI.HandleFunc("/admin/api/repeaters/update", handleAdminUpdateRepeater(db))
|
adminAPI.HandleFunc("/admin/api/repeaters/update", handleAdminUpdateRepeater(db))
|
||||||
adminAPI.HandleFunc("/admin/api/repeaters/bm-device", handleBMDevice())
|
adminAPI.HandleFunc("/admin/api/repeaters/bm-device", handleBMDevice())
|
||||||
adminAPI.HandleFunc("/admin/api/repeaters/save-bm", handleAdminSaveBMData(db))
|
adminAPI.HandleFunc("/admin/api/repeaters/save-bm", handleAdminSaveBMData(db))
|
||||||
|
adminAPI.HandleFunc("/admin/api/repeaters/remove-bm-tag", handleAdminRemoveBMTag(db))
|
||||||
mux.Handle("/admin/api/", adminAuth(adminToken, adminAPI))
|
mux.Handle("/admin/api/", adminAuth(adminToken, adminAPI))
|
||||||
log.Println("Admin interface enabled at /admin/")
|
log.Println("Admin interface enabled at /admin/")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -859,17 +859,15 @@
|
||||||
// --- Bulk BM fetch ---
|
// --- Bulk BM fetch ---
|
||||||
|
|
||||||
function fetchAllBMData() {
|
function fetchAllBMData() {
|
||||||
var bmRepeaters = currentRepeaters.filter(function (r) {
|
if (!currentRepeaters.length) {
|
||||||
return r.networks && r.networks.indexOf("Brandmeister") !== -1;
|
totalInfo.textContent = "No repeaters on this page";
|
||||||
});
|
|
||||||
if (!bmRepeaters.length) {
|
|
||||||
totalInfo.textContent = "No BrandMeister repeaters on this page";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var allRepeaters = currentRepeaters;
|
||||||
pendingBMData = {};
|
pendingBMData = {};
|
||||||
fetchAllBmBtn.disabled = true;
|
fetchAllBmBtn.disabled = true;
|
||||||
fetchAllBmBtn.textContent = "Fetching 0/" + bmRepeaters.length;
|
fetchAllBmBtn.textContent = "Fetching 0/" + allRepeaters.length;
|
||||||
|
|
||||||
var idx = 0;
|
var idx = 0;
|
||||||
var changed = 0;
|
var changed = 0;
|
||||||
|
|
@ -880,13 +878,13 @@
|
||||||
// 5s pause after every 10 fetches, otherwise 500ms (2/sec max)
|
// 5s pause after every 10 fetches, otherwise 500ms (2/sec max)
|
||||||
var delay = (fetched > 0 && fetched % 10 === 0) ? 5000 : 500;
|
var delay = (fetched > 0 && fetched % 10 === 0) ? 5000 : 500;
|
||||||
if (fetched > 0 && fetched % 10 === 0) {
|
if (fetched > 0 && fetched % 10 === 0) {
|
||||||
fetchAllBmBtn.textContent = "Pausing... " + idx + "/" + bmRepeaters.length;
|
fetchAllBmBtn.textContent = "Pausing... " + idx + "/" + allRepeaters.length;
|
||||||
}
|
}
|
||||||
setTimeout(next, delay);
|
setTimeout(next, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
if (idx >= bmRepeaters.length) {
|
if (idx >= allRepeaters.length) {
|
||||||
fetchAllBmBtn.disabled = false;
|
fetchAllBmBtn.disabled = false;
|
||||||
fetchAllBmBtn.textContent = "Fetch All BM";
|
fetchAllBmBtn.textContent = "Fetch All BM";
|
||||||
if (changed > 0) {
|
if (changed > 0) {
|
||||||
|
|
@ -899,8 +897,8 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var r = bmRepeaters[idx];
|
var r = allRepeaters[idx];
|
||||||
fetchAllBmBtn.textContent = "Fetching " + (idx + 1) + "/" + bmRepeaters.length;
|
fetchAllBmBtn.textContent = "Fetching " + (idx + 1) + "/" + allRepeaters.length;
|
||||||
|
|
||||||
apiFetch("/admin/api/repeaters/bm-device?id=" + r.id)
|
apiFetch("/admin/api/repeaters/bm-device?id=" + r.id)
|
||||||
.then(function (bm) {
|
.then(function (bm) {
|
||||||
|
|
@ -914,6 +912,13 @@
|
||||||
(bm.website || "") !== (r.website || "") ||
|
(bm.website || "") !== (r.website || "") ||
|
||||||
(bm.description || "") !== (r.description || "");
|
(bm.description || "") !== (r.description || "");
|
||||||
|
|
||||||
|
// If valid BM master and repeater lacks Brandmeister tag, mark as changed
|
||||||
|
var validMaster = bm.last_known_master && bm.last_known_master !== 0 && bm.last_known_master !== 9999;
|
||||||
|
if (validMaster && (!r.networks || r.networks.indexOf("Brandmeister") === -1)) {
|
||||||
|
hasChange = true;
|
||||||
|
bm._add_bm_tag = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasChange) {
|
if (hasChange) {
|
||||||
pendingBMData[r.id] = bm;
|
pendingBMData[r.id] = bm;
|
||||||
changed++;
|
changed++;
|
||||||
|
|
@ -924,7 +929,15 @@
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
if (err.message === "unauthorized") return;
|
if (err.message === "unauthorized") return;
|
||||||
|
if (err.message === "HTTP 404") {
|
||||||
|
// Not on BrandMeister — if it has the tag, mark for removal
|
||||||
|
if (r.networks && r.networks.indexOf("Brandmeister") !== -1) {
|
||||||
|
pendingBMData[r.id] = { _remove_bm_tag: true };
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
errors++;
|
errors++;
|
||||||
|
}
|
||||||
idx++;
|
idx++;
|
||||||
fetched++;
|
fetched++;
|
||||||
scheduleNext();
|
scheduleNext();
|
||||||
|
|
@ -963,7 +976,15 @@
|
||||||
var bm = pendingBMData[id];
|
var bm = pendingBMData[id];
|
||||||
bmReviewText.textContent = "Saving " + (idx + 1) + "/" + ids.length + "...";
|
bmReviewText.textContent = "Saving " + (idx + 1) + "/" + ids.length + "...";
|
||||||
|
|
||||||
apiFetch("/admin/api/repeaters/save-bm", {
|
var req;
|
||||||
|
if (bm._remove_bm_tag) {
|
||||||
|
req = apiFetch("/admin/api/repeaters/remove-bm-tag", {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ id: id })
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
req = apiFetch("/admin/api/repeaters/save-bm", {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|
@ -976,10 +997,12 @@
|
||||||
pep: bm.pep || 0,
|
pep: bm.pep || 0,
|
||||||
agl: bm.agl || 0,
|
agl: bm.agl || 0,
|
||||||
website: bm.website || "",
|
website: bm.website || "",
|
||||||
description: bm.description || ""
|
description: bm.description || "",
|
||||||
|
last_known_master: bm.last_known_master || 0
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
.then(function () { saved++; idx++; nextSave(); })
|
}
|
||||||
|
req.then(function () { saved++; idx++; nextSave(); })
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
if (err.message === "unauthorized") return;
|
if (err.message === "unauthorized") return;
|
||||||
errors++;
|
errors++;
|
||||||
|
|
@ -1042,7 +1065,11 @@
|
||||||
repeaters.forEach(function (r, idx) {
|
repeaters.forEach(function (r, idx) {
|
||||||
var tr = document.createElement("tr");
|
var tr = document.createElement("tr");
|
||||||
var bm = pendingBMData[r.id];
|
var bm = pendingBMData[r.id];
|
||||||
if (bm) tr.className = "bm-changed";
|
if (bm && bm._remove_bm_tag) {
|
||||||
|
tr.className = "bm-error";
|
||||||
|
} else if (bm) {
|
||||||
|
tr.className = "bm-changed";
|
||||||
|
}
|
||||||
|
|
||||||
var bandTag = r.band === "2m"
|
var bandTag = r.band === "2m"
|
||||||
? '<span class="tag tag-2m">2m</span>'
|
? '<span class="tag tag-2m">2m</span>'
|
||||||
|
|
@ -1052,9 +1079,9 @@
|
||||||
? '<span class="tag tag-inactive">Inactive</span>'
|
? '<span class="tag tag-inactive">Inactive</span>'
|
||||||
: '<span class="tag tag-active">' + escapeHtml(r.status) + '</span>';
|
: '<span class="tag tag-active">' + escapeHtml(r.status) + '</span>';
|
||||||
|
|
||||||
var bmStatusVal = bm ? bm.status_text || (bm.status !== null ? "Code " + bm.status : "") : r.bm_status_text || (r.bm_status !== null ? "Code " + r.bm_status : "");
|
var bmStatusVal = (bm && !bm._remove_bm_tag) ? bm.status_text || (bm.status !== null ? "Code " + bm.status : "") : r.bm_status_text || (r.bm_status !== null ? "Code " + r.bm_status : "");
|
||||||
var lastSeenVal = bm ? bm.last_seen : r.last_seen;
|
var lastSeenVal = (bm && !bm._remove_bm_tag) ? bm.last_seen : r.last_seen;
|
||||||
var hardwareVal = bm ? bm.hardware : r.hardware;
|
var hardwareVal = (bm && !bm._remove_bm_tag) ? bm.hardware : r.hardware;
|
||||||
|
|
||||||
tr.innerHTML =
|
tr.innerHTML =
|
||||||
'<td>' + r.id + '</td>' +
|
'<td>' + r.id + '</td>' +
|
||||||
|
|
@ -1359,6 +1386,21 @@
|
||||||
}
|
}
|
||||||
editingRepeater.bm_status = bm.status;
|
editingRepeater.bm_status = bm.status;
|
||||||
editingRepeater.bm_status_text = bm.status_text || "";
|
editingRepeater.bm_status_text = bm.status_text || "";
|
||||||
|
|
||||||
|
// Auto-add Brandmeister tag if valid master
|
||||||
|
var validMaster = bm.last_known_master && bm.last_known_master !== 0 && bm.last_known_master !== 9999;
|
||||||
|
if (validMaster && (!editingRepeater.networks || editingRepeater.networks.indexOf("Brandmeister") === -1)) {
|
||||||
|
if (!editingRepeater.networks) editingRepeater.networks = [];
|
||||||
|
editingRepeater.networks.push("Brandmeister");
|
||||||
|
// Check the Brandmeister checkbox in the form
|
||||||
|
var netGroup = detailBody.querySelector('[data-key="networks"]');
|
||||||
|
if (netGroup) {
|
||||||
|
var cbs = netGroup.querySelectorAll('input[type="checkbox"]');
|
||||||
|
for (var ci = 0; ci < cbs.length; ci++) {
|
||||||
|
if (cbs[ci].value === "Brandmeister") cbs[ci].checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveStatus.textContent = "BM data loaded — review and save";
|
saveStatus.textContent = "BM data loaded — review and save";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue