Stripped from the internal repo: per-box deploy trees, Go services (nodelist/astmeta/proxy/svxdr), deploy/sync scripts and all secrets. Config templates for nginx, PHP-FPM, Redis and tmpfiles live in install/ with CHANGEME placeholders. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
83 lines
3.8 KiB
JavaScript
83 lines
3.8 KiB
JavaScript
'use strict';
|
|
// Request a TG — mirrors the DMR tgrequest flow. Submit -> pending -> an admin
|
|
// approves (in the admin TG editor) -> you become owner. One open request/user.
|
|
var $ = function (id) { return document.getElementById(id); };
|
|
function esc(s) { var d = document.createElement('div'); d.textContent = s == null ? '' : String(s); return d.innerHTML; }
|
|
function reqMsg(t, err) { var e = $('reqMsg'); if (!e) return; if (!t) { e.style.display = 'none'; return; } e.style.display = 'block'; e.textContent = t; e.style.color = err ? '#ff8080' : '#0f0'; }
|
|
|
|
async function reqApi(body) {
|
|
var r = await fetch('/auth/tglist_api.php', {
|
|
method: 'POST', credentials: 'same-origin',
|
|
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': window._csrfToken || '' },
|
|
body: JSON.stringify(body)
|
|
});
|
|
return r.json().catch(function () { return null; });
|
|
}
|
|
|
|
function showPending(p) {
|
|
var box = $('reqPending'), form = $('reqForm'), cancel = $('reqCancel');
|
|
if (p) {
|
|
box.style.display = 'block';
|
|
box.innerHTML = 'You have a pending request for <b>TG ' + esc(p.tg) + '</b> ("' + esc(p.name) + '"). An admin will review it.';
|
|
// lock the form fields to the pending values
|
|
$('reqTg').value = p.tg; $('reqName').value = p.name || ''; $('reqSystem').value = p.system || '';
|
|
$('reqAllstar').value = p.allstar || ''; $('reqMode').value = p.mode || '';
|
|
Array.prototype.forEach.call(form.querySelectorAll('input'), function (i) { i.disabled = true; });
|
|
$('reqSubmit').disabled = true;
|
|
cancel.style.display = '';
|
|
} else {
|
|
box.style.display = 'none';
|
|
Array.prototype.forEach.call(form.querySelectorAll('input'), function (i) { i.disabled = false; });
|
|
$('reqSubmit').disabled = false;
|
|
cancel.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
async function loadPending() {
|
|
var j = await reqApi({ action: 'my_request' });
|
|
if (j && j.ok) showPending(j.pending || null);
|
|
}
|
|
|
|
var ERRS = {
|
|
no_callsign: 'Your account has no callsign — set one in your profile first.',
|
|
invalid_tg: 'Enter a valid TG number.',
|
|
tg_already_taken: 'That TG already exists.',
|
|
pending_request_exists: 'You already have a pending request.',
|
|
name_required: 'Name is required.',
|
|
invalid_allstar: 'AllStar node must be digits only.'
|
|
};
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
fetch('/auth/me.php', { credentials: 'same-origin' })
|
|
.then(function (r) { return r.json(); })
|
|
.then(function (j) {
|
|
if (j && j.csrf_token) window._csrfToken = j.csrf_token;
|
|
var cs = (j && j.callsign) ? String(j.callsign).toUpperCase() : '';
|
|
var el = $('reqCallsign');
|
|
if (el) el.innerHTML = cs ? esc(cs) : '<span style="color:#ff8080;">No callsign on your account — set one in your profile first.</span>';
|
|
})
|
|
.catch(function () {})
|
|
.finally(loadPending);
|
|
|
|
$('reqForm').addEventListener('submit', async function (e) {
|
|
e.preventDefault();
|
|
var tg = parseInt($('reqTg').value, 10);
|
|
if (!tg || tg <= 0) { reqMsg('Enter a valid TG number', true); return; }
|
|
if (!($('reqName').value || '').trim()) { reqMsg('Name is required', true); return; }
|
|
var res = await reqApi({
|
|
action: 'request', tg: tg,
|
|
name: $('reqName').value, system: $('reqSystem').value,
|
|
allstar: ($('reqAllstar').value || '').trim(), mode: $('reqMode').value
|
|
});
|
|
if (res && res.ok) { reqMsg('Request submitted — awaiting admin approval.', false); await loadPending(); }
|
|
else reqMsg(ERRS[res && res.error] || (res && res.error) || 'Failed', true);
|
|
});
|
|
|
|
$('reqCancel').addEventListener('click', async function () {
|
|
if (!confirm('Cancel your pending TG request?')) return;
|
|
var res = await reqApi({ action: 'request_cancel' });
|
|
if (res && res.ok) { reqMsg('Request cancelled.', false); await loadPending(); }
|
|
else reqMsg((res && res.error) || 'Failed', true);
|
|
});
|
|
});
|