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"`
|
||||
Website string `json:"website"`
|
||||
Description string `json:"description"`
|
||||
LastKnownMaster int `json:"last_known_master"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
|
||||
|
|
@ -228,6 +229,42 @@ func handleAdminSaveBMData(db *sql.DB) http.HandlerFunc {
|
|||
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.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/bm-device", handleBMDevice())
|
||||
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))
|
||||
log.Println("Admin interface enabled at /admin/")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -859,17 +859,15 @@
|
|||
// --- Bulk BM fetch ---
|
||||
|
||||
function fetchAllBMData() {
|
||||
var bmRepeaters = currentRepeaters.filter(function (r) {
|
||||
return r.networks && r.networks.indexOf("Brandmeister") !== -1;
|
||||
});
|
||||
if (!bmRepeaters.length) {
|
||||
totalInfo.textContent = "No BrandMeister repeaters on this page";
|
||||
if (!currentRepeaters.length) {
|
||||
totalInfo.textContent = "No repeaters on this page";
|
||||
return;
|
||||
}
|
||||
|
||||
var allRepeaters = currentRepeaters;
|
||||
pendingBMData = {};
|
||||
fetchAllBmBtn.disabled = true;
|
||||
fetchAllBmBtn.textContent = "Fetching 0/" + bmRepeaters.length;
|
||||
fetchAllBmBtn.textContent = "Fetching 0/" + allRepeaters.length;
|
||||
|
||||
var idx = 0;
|
||||
var changed = 0;
|
||||
|
|
@ -880,13 +878,13 @@
|
|||
// 5s pause after every 10 fetches, otherwise 500ms (2/sec max)
|
||||
var delay = (fetched > 0 && fetched % 10 === 0) ? 5000 : 500;
|
||||
if (fetched > 0 && fetched % 10 === 0) {
|
||||
fetchAllBmBtn.textContent = "Pausing... " + idx + "/" + bmRepeaters.length;
|
||||
fetchAllBmBtn.textContent = "Pausing... " + idx + "/" + allRepeaters.length;
|
||||
}
|
||||
setTimeout(next, delay);
|
||||
}
|
||||
|
||||
function next() {
|
||||
if (idx >= bmRepeaters.length) {
|
||||
if (idx >= allRepeaters.length) {
|
||||
fetchAllBmBtn.disabled = false;
|
||||
fetchAllBmBtn.textContent = "Fetch All BM";
|
||||
if (changed > 0) {
|
||||
|
|
@ -899,8 +897,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
var r = bmRepeaters[idx];
|
||||
fetchAllBmBtn.textContent = "Fetching " + (idx + 1) + "/" + bmRepeaters.length;
|
||||
var r = allRepeaters[idx];
|
||||
fetchAllBmBtn.textContent = "Fetching " + (idx + 1) + "/" + allRepeaters.length;
|
||||
|
||||
apiFetch("/admin/api/repeaters/bm-device?id=" + r.id)
|
||||
.then(function (bm) {
|
||||
|
|
@ -914,6 +912,13 @@
|
|||
(bm.website || "") !== (r.website || "") ||
|
||||
(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) {
|
||||
pendingBMData[r.id] = bm;
|
||||
changed++;
|
||||
|
|
@ -924,7 +929,15 @@
|
|||
})
|
||||
.catch(function (err) {
|
||||
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++;
|
||||
}
|
||||
idx++;
|
||||
fetched++;
|
||||
scheduleNext();
|
||||
|
|
@ -963,7 +976,15 @@
|
|||
var bm = pendingBMData[id];
|
||||
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",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
|
|
@ -976,10 +997,12 @@
|
|||
pep: bm.pep || 0,
|
||||
agl: bm.agl || 0,
|
||||
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) {
|
||||
if (err.message === "unauthorized") return;
|
||||
errors++;
|
||||
|
|
@ -1042,7 +1065,11 @@
|
|||
repeaters.forEach(function (r, idx) {
|
||||
var tr = document.createElement("tr");
|
||||
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"
|
||||
? '<span class="tag tag-2m">2m</span>'
|
||||
|
|
@ -1052,9 +1079,9 @@
|
|||
? '<span class="tag tag-inactive">Inactive</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 lastSeenVal = bm ? bm.last_seen : r.last_seen;
|
||||
var hardwareVal = bm ? bm.hardware : r.hardware;
|
||||
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._remove_bm_tag) ? bm.last_seen : r.last_seen;
|
||||
var hardwareVal = (bm && !bm._remove_bm_tag) ? bm.hardware : r.hardware;
|
||||
|
||||
tr.innerHTML =
|
||||
'<td>' + r.id + '</td>' +
|
||||
|
|
@ -1359,6 +1386,21 @@
|
|||
}
|
||||
editingRepeater.bm_status = bm.status;
|
||||
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";
|
||||
|
|
|
|||
Loading…
Reference in a new issue