From 8c031a939c5109da9457321cd9606f30090705de Mon Sep 17 00:00:00 2001 From: oe6dxd-automation Date: Thu, 2 Apr 2026 22:42:49 +0200 Subject: [PATCH] split RMS login email into callsign and domain select --- public/app.js | 82 ++++++++++++++++++++++++++++++++++++++++++++--- public/index.html | 17 +++++++--- 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/public/app.js b/public/app.js index 20ae6f2..8169de3 100644 --- a/public/app.js +++ b/public/app.js @@ -81,7 +81,8 @@ const state = { const els = { authForm: document.getElementById("authForm"), - email: document.getElementById("email"), + callsignInput: document.getElementById("callsignInput"), + emailDomainSelect: document.getElementById("emailDomainSelect"), loginBtn: document.getElementById("loginBtn"), authMethodSelect: document.getElementById("authMethodSelect"), otpWrap: document.getElementById("otpWrap"), @@ -910,7 +911,7 @@ async function refreshFrontendOnResume() { async function requestAccess() { clearMessages("auth"); - const email = els.email.value.trim(); + const email = composeLoginEmail(); if (!isLoginEmailAllowed(email)) { renderMessage(els.authMessage, `Nur Club-Mailadressen (${formatAllowedDomainsHint()}) sind zum Anmelden moeglich.`, true); return; @@ -950,11 +951,12 @@ async function requestAccess() { async function verifyOtpCode() { clearMessages("auth"); + const email = composeLoginEmail(); try { const result = await api("/v1/auth/verify-email", { method: "POST", body: { - email: els.email.value.trim(), + email, code: els.otpCode.value.trim() }, authRequired: false @@ -997,6 +999,41 @@ function isLoginEmailAllowed(email) { return getAllowedLoginDomains().includes(domain); } +function composeLoginEmail() { + const callsign = String(els.callsignInput && els.callsignInput.value ? els.callsignInput.value : "") + .trim() + .toLowerCase(); + const selectedDomain = String( + els.emailDomainSelect && els.emailDomainSelect.value + ? els.emailDomainSelect.value + : getAllowedLoginDomains()[0] || "" + ) + .trim() + .toLowerCase(); + if (!callsign || !selectedDomain) { + return ""; + } + if (callsign.includes("@")) { + return callsign; + } + return `${callsign}@${selectedDomain}`; +} + +function splitEmailParts(email) { + const normalized = String(email || "").trim().toLowerCase(); + const atIndex = normalized.lastIndexOf("@"); + if (atIndex < 0) { + return { + callsign: normalized, + domain: "" + }; + } + return { + callsign: normalized.slice(0, atIndex), + domain: normalized.slice(atIndex + 1) + }; +} + function getAllowedLoginDomains() { const list = state && state.system && Array.isArray(state.system.allowedLoginDomains) ? state.system.allowedLoginDomains @@ -1008,12 +1045,32 @@ function formatAllowedDomainsHint() { return getAllowedLoginDomains().map((domain) => `@${domain}`).join(" oder "); } +function renderLoginDomainSelect() { + if (!els.emailDomainSelect) { + return; + } + const domains = getAllowedLoginDomains(); + const previous = String(els.emailDomainSelect.value || "").toLowerCase(); + els.emailDomainSelect.innerHTML = ""; + for (const domain of domains) { + const option = document.createElement("option"); + option.value = domain; + option.textContent = domain; + els.emailDomainSelect.appendChild(option); + } + if (previous && domains.includes(previous)) { + els.emailDomainSelect.value = previous; + } else if (domains.length > 0) { + els.emailDomainSelect.value = domains[0]; + } +} + async function handleEmailTokenFromUrl() { const url = new URL(window.location.href); if (url.searchParams.get("requestApproval") === "1") { const email = (url.searchParams.get("email") || "").trim(); if (email) { - els.email.value = email; + setLoginEmail(email); try { const result = await api("/v1/auth/request-approval", { method: "POST", @@ -1066,6 +1123,19 @@ async function handleEmailTokenFromUrl() { } } +function setLoginEmail(email) { + const parts = splitEmailParts(email); + if (els.callsignInput) { + els.callsignInput.value = parts.callsign || ""; + } + if (els.emailDomainSelect) { + renderLoginDomainSelect(); + if (parts.domain && getAllowedLoginDomains().includes(parts.domain)) { + els.emailDomainSelect.value = parts.domain; + } + } +} + async function refreshPublicSystemStatus() { try { const result = await api("/v1/public/system", { authRequired: false }); @@ -1085,6 +1155,7 @@ async function refreshPublicSystemStatus() { allowedLoginDomains: DEFAULT_ALLOWED_LOGIN_DOMAINS.slice() }; } + renderLoginDomainSelect(); renderMaintenanceBanner(); renderBranding(); } @@ -4225,7 +4296,8 @@ function updateUserUi() { setDisabled(els.logoutBtn, !loggedIn); setDisabled(els.settingsLogoutTopBtn, !loggedIn); setDisabled(els.userMenuButton, !loggedIn); - setDisabled(els.email, loggedIn); + setDisabled(els.callsignInput, loggedIn); + setDisabled(els.emailDomainSelect, loggedIn); if (els.userMenuButton) { els.userMenuButton.textContent = "☰"; els.userMenuButton.setAttribute("aria-label", loggedIn ? `Menue (${state.user.email})` : "Menue"); diff --git a/public/index.html b/public/index.html index 1eac437..29369f0 100644 --- a/public/index.html +++ b/public/index.html @@ -59,14 +59,21 @@