Files
gott/wwwroot/js/pages/admin-page.js
T
Meleki 1a2c407538 refactor(frontend): Duplikate in JS eliminieren – Runde 2
Neue Helper-Funktionen:
- _openCardMenu(trigger, dropdown): Card-Menü-Positionierung (4x in dashboard.js dedupliziert)
- _createModal(title, extraClasses): Modal-Boilerplate (3 Modals in modals.js dedupliziert)
- _openPickerModal(title, items, currentId, onSelect, opts): Picker-Modal (Agent + Session zusammengeführt)
- createMDE(element, opts): EasyMDE-Initialisierung (3x in agent/session/profile-page dedupliziert)

Weitere Bereinigungen:
- _formatReplyTimestamp() entfernt, durch _formatTimestamp() ersetzt (reply.js + chat.js)
- showFormMessage/showPageMessage in admin-page.js durch showToast() ersetzt
- Inline-Nachrichten (profileMessage, profilePasswordMessage, adminMessage, adminFormMessage) durch Toast-Notifications ersetzt, zugehörige HTML-Elemente entfernt
- profile-page.js: messageDiv/passwordMessageDiv-Logik durch showToast() ersetzt

11 Dateien, -210 Zeilen netto
2026-03-07 21:50:23 +01:00

293 lines
9.4 KiB
JavaScript

// ── Admin Page (User Management) ──
registerPage('admin', {
async init() {
if (!currentUser || !currentUser.isAdmin) {
navigateTo('dashboard');
return;
}
var users = [];
var editingUserId = null;
var list = document.getElementById('adminUserList');
var newUserBtn = document.getElementById('adminNewUserBtn');
var userForm = document.getElementById('adminUserForm');
var formTitle = document.getElementById('adminFormTitle');
var usernameInput = document.getElementById('adminUsername');
var displayNameInput = document.getElementById('adminDisplayName');
var passwordInput = document.getElementById('adminPassword');
var passwordLabel = document.getElementById('adminPasswordLabel');
var defaultPathInput = document.getElementById('adminDefaultPath');
var defaultPathBrowse = document.getElementById('adminDefaultPathBrowse');
var isAdminCheckbox = document.getElementById('adminIsAdmin');
var saveBtn = document.getElementById('adminFormSaveBtn');
function renderUsers() {
list.innerHTML = '';
users.forEach(function(user) {
var row = document.createElement('div');
row.className = 'admin-user-row';
var info = document.createElement('div');
info.className = 'admin-user-info';
var nameSpan = document.createElement('span');
nameSpan.className = 'admin-user-name';
nameSpan.textContent = user.displayName || user.username;
var metaSpan = document.createElement('span');
metaSpan.className = 'admin-user-meta';
var metaParts = ['@' + user.username];
if (user.isAdmin) metaParts.push('Administrator');
if (user.defaultPath) metaParts.push(user.defaultPath);
metaSpan.textContent = metaParts.join(' · ');
info.appendChild(nameSpan);
info.appendChild(metaSpan);
var actions = document.createElement('div');
actions.className = 'admin-user-actions';
var editBtn = document.createElement('button');
editBtn.className = 'icon-btn';
editBtn.title = 'Bearbeiten';
editBtn.innerHTML = '<i class="fa fa-pencil"></i>';
editBtn.addEventListener('click', function() {
startEdit(user);
});
actions.appendChild(editBtn);
// Login-Link + Löschen (nicht für sich selbst)
if (user.userId !== currentUser.userId) {
var linkBtn = document.createElement('button');
linkBtn.className = 'icon-btn';
linkBtn.title = 'Login-Link generieren';
linkBtn.innerHTML = '<i class="fa fa-link"></i>';
linkBtn.addEventListener('click', function() {
generateLoginLink(user);
});
actions.appendChild(linkBtn);
var deleteBtn = document.createElement('button');
deleteBtn.className = 'icon-btn';
deleteBtn.title = 'Löschen';
deleteBtn.innerHTML = '<i class="fa fa-trash"></i>';
deleteBtn.addEventListener('click', function() {
deleteUser(user);
});
actions.appendChild(deleteBtn);
}
row.appendChild(info);
row.appendChild(actions);
list.appendChild(row);
});
}
async function loadUsers() {
try {
users = await apiAdminGetUsers();
renderUsers();
} catch (err) {
showToast(err.message, 'error');
}
}
function startEdit(user) {
editingUserId = user.userId;
formTitle.textContent = 'Benutzer bearbeiten';
usernameInput.value = user.username;
usernameInput.disabled = false;
displayNameInput.value = user.displayName || '';
passwordInput.value = '';
passwordLabel.textContent = 'Neues Passwort (leer = unverändert)';
passwordInput.placeholder = 'Neues Passwort (optional)';
passwordInput.required = false;
defaultPathInput.value = user.defaultPath || '';
isAdminCheckbox.checked = user.isAdmin;
saveBtn.textContent = 'Speichern';
userForm.hidden = false;
usernameInput.focus();
}
async function deleteUser(user) {
if (!confirm('Benutzer "' + (user.displayName || user.username) + '" wirklich löschen?\n\nAlle Tokens werden ebenfalls gelöscht.')) {
return;
}
try {
await apiAdminDeleteUser(user.userId);
await loadUsers();
} catch (err) {
showToast(err.message, 'error');
}
}
async function generateLoginLink(user) {
try {
var result = await apiAdminGetLoginLink(user.userId);
var link = window.location.origin + '/api/auth/autologin?token=' + result.token;
showLoginLinkModal(user, link);
} catch (err) {
showToast(err.message, 'error');
}
}
function showLoginLinkModal(user, link) {
// Entferne vorherigen Modal falls vorhanden
var existing = document.querySelector('.login-link-overlay');
if (existing) existing.remove();
var overlay = document.createElement('div');
overlay.className = 'login-link-overlay';
var modal = document.createElement('div');
modal.className = 'login-link-modal';
var title = document.createElement('h3');
title.textContent = 'Login-Link für ' + (user.displayName || user.username);
var desc = document.createElement('p');
desc.className = 'login-link-desc';
desc.textContent = 'Dieser Link loggt automatisch als dieser Benutzer ein. Teile ihn nur mit vertrauenswürdigen Personen.';
var inputRow = document.createElement('div');
inputRow.className = 'login-link-input-row';
var input = document.createElement('input');
input.type = 'text';
input.readOnly = true;
input.value = link;
input.className = 'login-link-input';
var copyBtn = document.createElement('button');
copyBtn.className = 'btn btn-primary';
copyBtn.innerHTML = '<i class="fa fa-copy"></i> Kopieren';
copyBtn.addEventListener('click', function() {
navigator.clipboard.writeText(link).then(function() {
copyBtn.innerHTML = '<i class="fa fa-check"></i> Kopiert!';
setTimeout(function() {
copyBtn.innerHTML = '<i class="fa fa-copy"></i> Kopieren';
}, 2000);
});
});
inputRow.appendChild(input);
inputRow.appendChild(copyBtn);
var closeBtn = document.createElement('button');
closeBtn.className = 'btn';
closeBtn.textContent = 'Schließen';
closeBtn.addEventListener('click', function() {
overlay.remove();
});
modal.appendChild(title);
modal.appendChild(desc);
modal.appendChild(inputRow);
modal.appendChild(closeBtn);
overlay.appendChild(modal);
overlay.addEventListener('click', function(e) {
if (e.target === overlay) overlay.remove();
});
document.body.appendChild(overlay);
// Input selektieren für einfaches Kopieren
input.select();
}
// ── Event-Listener ──
// Default Path Browse
if (defaultPathBrowse) {
defaultPathBrowse.addEventListener('click', function() {
openFolderBrowser({
startPath: defaultPathInput.value.trim() || '/',
onSelect: function(path) {
defaultPathInput.value = path;
}
});
});
}
// Neuer Benutzer
newUserBtn.addEventListener('click', function() {
editingUserId = null;
formTitle.textContent = 'Neuer Benutzer';
usernameInput.value = '';
usernameInput.disabled = false;
displayNameInput.value = '';
passwordInput.value = '';
passwordLabel.textContent = 'Passwort';
passwordInput.placeholder = 'Passwort';
passwordInput.required = true;
defaultPathInput.value = '';
isAdminCheckbox.checked = false;
saveBtn.textContent = 'Erstellen';
userForm.hidden = false;
usernameInput.focus();
});
// Speichern
saveBtn.addEventListener('click', async function() {
saveBtn.disabled = true;
try {
if (editingUserId) {
// Update
var data = {
username: usernameInput.value.trim(),
displayName: displayNameInput.value.trim(),
defaultPath: defaultPathInput.value.trim() || null,
isAdmin: isAdminCheckbox.checked
};
await apiAdminUpdateUser(editingUserId, data);
// Passwort nur wenn ausgefüllt
var pw = passwordInput.value;
if (pw) {
await apiAdminResetPassword(editingUserId, pw);
}
showToast('Benutzer aktualisiert');
} else {
// Create
var username = usernameInput.value.trim();
var password = passwordInput.value;
if (!username || !password) {
showToast('Benutzername und Passwort erforderlich', 'error');
return;
}
await apiAdminCreateUser({
username: username,
password: password,
displayName: displayNameInput.value.trim(),
defaultPath: defaultPathInput.value.trim() || null,
isAdmin: isAdminCheckbox.checked
});
showToast('Benutzer erstellt');
}
userForm.hidden = true;
await loadUsers();
} catch (err) {
showToast(err.message, 'error');
} finally {
saveBtn.disabled = false;
}
});
// ── Init: User laden ──
await loadUsers();
},
destroy() {}
});