- Rollensystem: Public → Mitarbeiter → Admin (Rolle user entfällt) - DB-Migration: must_change_password-Spalte, user→mitarbeiter - require_staff_api(): erlaubt mitarbeiter + admin - POST /api/admin/invite: Einladung mit auto-generiertem Passwort + E-Mail - POST /auth/change-password: Pflicht-Passwortwechsel - Login: force_password_change-Redirect - Sidebar: sidebar-staff für Scheduler/NINA/Einstellungen - Scheduler/NINA: read-only für Mitarbeiter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
66 lines
2.1 KiB
JavaScript
66 lines
2.1 KiB
JavaScript
// MeshDD-Dashboard – Pflicht-Passwortwechsel
|
||
|
||
// Theme
|
||
(function () {
|
||
const t = localStorage.getItem('theme') || 'light';
|
||
document.documentElement.setAttribute('data-bs-theme', t);
|
||
})();
|
||
|
||
// Footer
|
||
(function () {
|
||
const footer = document.getElementById('cpFooter');
|
||
if (!footer) return;
|
||
const now = new Date();
|
||
const mm = String(now.getMonth() + 1).padStart(2, '0');
|
||
fetch('/api/stats').then(r => r.ok ? r.json() : null).then(d => {
|
||
const ver = d?.version ? ` · v${d.version}` : '';
|
||
footer.textContent = `© MeshDD / PPfeiffer${ver} · ${mm}/${now.getFullYear()}`;
|
||
}).catch(() => {});
|
||
})();
|
||
|
||
// Guard: redirect to login if not logged in
|
||
fetch('/api/auth/me').then(r => {
|
||
if (!r.ok) window.location.href = '/login';
|
||
}).catch(() => { window.location.href = '/login'; });
|
||
|
||
function showAlert(msg, type = 'danger') {
|
||
const el = document.getElementById('cpAlert');
|
||
el.className = `alert alert-${type} py-1 small`;
|
||
el.textContent = msg;
|
||
}
|
||
|
||
document.getElementById('btnChangePassword').addEventListener('click', async () => {
|
||
const password = document.getElementById('cpPassword').value;
|
||
const confirm = document.getElementById('cpConfirm').value;
|
||
|
||
if (password.length < 8) {
|
||
showAlert('Passwort muss mindestens 8 Zeichen lang sein');
|
||
return;
|
||
}
|
||
if (password !== confirm) {
|
||
showAlert('Passwoerter stimmen nicht ueberein');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const resp = await fetch('/auth/change-password', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ password }),
|
||
});
|
||
const data = await resp.json();
|
||
if (resp.ok) {
|
||
showAlert(data.message || 'Passwort geaendert', 'success');
|
||
setTimeout(() => { window.location.href = '/'; }, 1500);
|
||
} else {
|
||
showAlert(data.error || 'Fehler beim Aendern');
|
||
}
|
||
} catch (e) {
|
||
showAlert('Verbindungsfehler');
|
||
}
|
||
});
|
||
|
||
document.getElementById('cpConfirm').addEventListener('keydown', (e) => {
|
||
if (e.key === 'Enter') document.getElementById('btnChangePassword').click();
|
||
});
|