user admin
This commit is contained in:
+76
-2
@@ -32,6 +32,13 @@ const elements = {
|
||||
format: document.querySelector("#audio-format"),
|
||||
source: document.querySelector("#audio-source"),
|
||||
status: document.querySelector("#status"),
|
||||
logout: document.querySelector("#logout"),
|
||||
loginOverlay: document.querySelector("#login-overlay"),
|
||||
loginForm: document.querySelector("#login-form"),
|
||||
loginUsername: document.querySelector("#login-username"),
|
||||
loginPassword: document.querySelector("#login-password"),
|
||||
loginError: document.querySelector("#login-error"),
|
||||
loginSubmit: document.querySelector("#login-submit"),
|
||||
};
|
||||
|
||||
let state = null;
|
||||
@@ -39,6 +46,14 @@ let seekBusy = false;
|
||||
let draggedTrack = null;
|
||||
let commandBusy = false;
|
||||
|
||||
class ApiError extends Error {
|
||||
constructor(message, status, code) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(value) {
|
||||
if (!Number.isFinite(value) || value < 0) return "00:00:00";
|
||||
const whole = Math.floor(value);
|
||||
@@ -62,10 +77,34 @@ async function api(path, body) {
|
||||
};
|
||||
const response = await fetch(path, options);
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw new Error(data.error || `HTTP ${response.status}`);
|
||||
if (!response.ok) {
|
||||
throw new ApiError(data.error || `HTTP ${response.status}`, response.status, data.code);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function showLogin(message = null) {
|
||||
if (message !== null) elements.loginError.textContent = message;
|
||||
elements.loginOverlay.hidden = false;
|
||||
window.setTimeout(() => elements.loginUsername.focus(), 0);
|
||||
}
|
||||
|
||||
function hideLogin() {
|
||||
elements.loginOverlay.hidden = true;
|
||||
elements.loginError.textContent = "";
|
||||
elements.loginPassword.value = "";
|
||||
}
|
||||
|
||||
async function refreshAuth() {
|
||||
try {
|
||||
const auth = await api("/api/auth/status");
|
||||
elements.logout.hidden = !auth.enabled || auth.local || !auth.authenticated;
|
||||
if (auth.enabled && !auth.local && !auth.authenticated) showLogin();
|
||||
} catch (error) {
|
||||
setStatus(`Authenticatiestatus onbekend: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function command(name, data = {}, pendingMessage = "") {
|
||||
if (pendingMessage) setStatus(pendingMessage);
|
||||
commandBusy = true;
|
||||
@@ -441,10 +480,45 @@ async function refresh() {
|
||||
if (commandBusy) return;
|
||||
try {
|
||||
render(await api("/api/state"));
|
||||
hideLogin();
|
||||
} catch (error) {
|
||||
setStatus(`Geen verbinding: ${error.message}`);
|
||||
if (error.code === "authentication-required") {
|
||||
showLogin();
|
||||
} else {
|
||||
setStatus(`Geen verbinding: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elements.loginForm.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
elements.loginSubmit.disabled = true;
|
||||
elements.loginError.textContent = "";
|
||||
try {
|
||||
await api("/api/auth/login", {
|
||||
username: elements.loginUsername.value,
|
||||
password: elements.loginPassword.value,
|
||||
});
|
||||
hideLogin();
|
||||
await refreshAuth();
|
||||
await refresh();
|
||||
} catch (error) {
|
||||
showLogin(error.message);
|
||||
elements.loginPassword.select();
|
||||
} finally {
|
||||
elements.loginSubmit.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
elements.logout.addEventListener("click", async () => {
|
||||
try {
|
||||
await api("/api/auth/logout", {});
|
||||
} finally {
|
||||
elements.logout.hidden = true;
|
||||
showLogin("Je bent uitgelogd.");
|
||||
}
|
||||
});
|
||||
|
||||
refreshAuth();
|
||||
refresh();
|
||||
setInterval(refresh, 1000);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<label for="renderer">UITVOER</label>
|
||||
<select id="renderer"></select>
|
||||
<button id="discover" class="square-button" type="button" title="Netwerkspelers zoeken" aria-label="Netwerkspelers zoeken">↻</button>
|
||||
<button id="logout" class="text-button" type="button" hidden>UITLOGGEN</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -129,6 +130,20 @@
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<section id="login-overlay" class="login-overlay" aria-labelledby="login-title" hidden>
|
||||
<form id="login-form" class="login-panel">
|
||||
<span class="brand-mark">RKT</span>
|
||||
<p class="panel-kicker">WEB PLAYER</p>
|
||||
<h1 id="login-title">Aanmelden</h1>
|
||||
<label for="login-username">Gebruikersnaam</label>
|
||||
<input id="login-username" name="username" autocomplete="username" required>
|
||||
<label for="login-password">Wachtwoord</label>
|
||||
<input id="login-password" name="password" type="password" autocomplete="current-password" required>
|
||||
<p id="login-error" class="login-error" role="alert"></p>
|
||||
<button id="login-submit" class="text-button" type="submit">AANMELDEN</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<script src="/app.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -198,6 +198,55 @@ input[type="range"] {
|
||||
accent-color: var(--accent);
|
||||
}
|
||||
|
||||
.login-overlay {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
background: rgb(10 10 10 / 82%);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.login-overlay[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.login-panel {
|
||||
display: grid;
|
||||
width: min(390px, 100%);
|
||||
gap: 9px;
|
||||
padding: 28px;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--panel);
|
||||
box-shadow: 0 24px 80px rgb(0 0 0 / 55%);
|
||||
}
|
||||
|
||||
.login-panel h1 {
|
||||
margin: 8px 0 14px;
|
||||
}
|
||||
|
||||
.login-panel input {
|
||||
min-width: 0;
|
||||
margin-bottom: 8px;
|
||||
padding: 10px 11px;
|
||||
border: 1px solid var(--line);
|
||||
color: var(--text);
|
||||
background: #111;
|
||||
}
|
||||
|
||||
.login-panel .text-button {
|
||||
justify-self: start;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.login-error {
|
||||
min-height: 1.3em;
|
||||
margin: 0;
|
||||
color: #ff796f;
|
||||
}
|
||||
|
||||
.time-display {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
|
||||
Reference in New Issue
Block a user