Title: Enhanced System Logs and UI Updates

🎉 New system logs have been implemented for improved monitoring and debugging capabilities. These include:

- admin.log
- admin_api.log
- app.log
- data_management.log
- drucker_steuerung.log
- energy_monitoring.log
- hardware_integration.log
- job_queue_system.log
- monitoring_analytics.log
- permissions.
This commit is contained in:
2025-06-20 00:41:55 +02:00
parent f9b5eafb76
commit 0fcf04833f
73 changed files with 1183 additions and 326 deletions

View File

@ -1083,6 +1083,208 @@ class AdminDashboard {
}
}
// ===== DIREKTE BENUTZERVERWALTUNGS-FUNKTIONEN =====
async updateUserRole(userId, newRole) {
try {
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify({ role: newRole })
});
const data = await response.json();
if (data.success) {
this.showNotification(`✅ Rolle erfolgreich aktualisiert`, 'success');
// Seite nach kurzer Zeit neu laden
setTimeout(() => window.location.reload(), 1000);
} else {
this.showNotification(`❌ Fehler: ${data.error}`, 'error');
// Rolle zurücksetzen bei Fehler
const selectElement = document.querySelector(`select[data-user-id="${userId}"]`);
if (selectElement) {
selectElement.value = selectElement.value === 'admin' ? 'user' : 'admin';
}
}
} catch (error) {
console.error('Fehler beim Aktualisieren der Rolle:', error);
this.showNotification('❌ Fehler beim Aktualisieren der Rolle', 'error');
}
}
async toggleUserStatus(userId, isActive) {
try {
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify({ active: isActive })
});
const data = await response.json();
if (data.success) {
const statusText = isActive ? 'aktiviert' : 'deaktiviert';
this.showNotification(`✅ Benutzer erfolgreich ${statusText}`, 'success');
// Status-Text visuell aktualisieren
const row = document.querySelector(`tr[data-user-id="${userId}"]`);
const statusSpan = row.querySelector('.status-toggle + span');
if (statusSpan) {
statusSpan.textContent = isActive ? 'Aktiv' : 'Inaktiv';
statusSpan.className = `ml-2 text-xs ${isActive ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}`;
}
} else {
this.showNotification(`❌ Fehler: ${data.error}`, 'error');
// Checkbox zurücksetzen
const checkbox = document.querySelector(`input[data-user-id="${userId}"].status-toggle`);
if (checkbox) checkbox.checked = !isActive;
}
} catch (error) {
console.error('Fehler beim Ändern des Status:', error);
this.showNotification('❌ Fehler beim Ändern des Status', 'error');
}
}
async updateUserPermission(userId, permission, isEnabled) {
try {
const permissionData = {
[permission]: isEnabled
};
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}/permissions`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify(permissionData)
});
const data = await response.json();
if (data.success) {
const permissionNames = {
'can_start_jobs': 'Jobs starten',
'needs_approval': 'Genehmigung erforderlich',
'can_approve_jobs': 'Jobs genehmigen'
};
const actionText = isEnabled ? 'aktiviert' : 'deaktiviert';
this.showNotification(`${permissionNames[permission]} ${actionText}`, 'success');
} else {
this.showNotification(`❌ Fehler: ${data.error}`, 'error');
// Checkbox zurücksetzen
const checkbox = document.querySelector(`input[data-user-id="${userId}"][data-permission="${permission}"]`);
if (checkbox) checkbox.checked = !isEnabled;
}
} catch (error) {
console.error('Fehler beim Aktualisieren der Berechtigung:', error);
this.showNotification('❌ Fehler beim Aktualisieren der Berechtigung', 'error');
}
}
async resetUserPassword(userId, userName) {
if (!confirm(`🔑 Möchten Sie das Passwort für "${userName}" wirklich zurücksetzen?\n\nDem Benutzer wird ein neues temporäres Passwort zugewiesen.`)) {
return;
}
try {
// Temporäres Passwort generieren
const tempPassword = this.generateTempPassword();
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify({ password: tempPassword })
});
const data = await response.json();
if (data.success) {
// Passwort-Modal anzeigen
this.showPasswordResetModal(userName, tempPassword);
} else {
this.showNotification(`❌ Fehler: ${data.error}`, 'error');
}
} catch (error) {
console.error('Fehler beim Zurücksetzen des Passworts:', error);
this.showNotification('❌ Fehler beim Zurücksetzen des Passworts', 'error');
}
}
generateTempPassword() {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789';
let password = '';
for (let i = 0; i < 12; i++) {
password += chars.charAt(Math.floor(Math.random() * chars.length));
}
return password;
}
showPasswordResetModal(userName, tempPassword) {
const modalHtml = `
<div id="password-reset-modal" class="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div class="bg-white dark:bg-slate-800 rounded-2xl p-8 max-w-md w-full shadow-2xl">
<div class="text-center mb-6">
<div class="w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
<svg class="w-8 h-8 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/>
</svg>
</div>
<h3 class="text-2xl font-bold text-slate-900 dark:text-white">Passwort zurückgesetzt</h3>
<p class="text-slate-600 dark:text-slate-400 mt-2">Neues temporäres Passwort für <strong>${userName}</strong></p>
</div>
<div class="bg-slate-50 dark:bg-slate-700 rounded-xl p-4 mb-6">
<div class="flex items-center justify-between">
<div class="font-mono text-lg font-bold text-slate-900 dark:text-white">${tempPassword}</div>
<button onclick="navigator.clipboard.writeText('${tempPassword}'); this.innerHTML='✓ Kopiert'"
class="px-3 py-1 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors text-sm">
Kopieren
</button>
</div>
</div>
<div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-xl p-4 mb-6">
<p class="text-sm text-yellow-800 dark:text-yellow-200">
<strong>Wichtig:</strong> Teilen Sie dieses Passwort sicher mit dem Benutzer mit und bitten Sie ihn, es sofort zu ändern.
</p>
</div>
<button onclick="document.getElementById('password-reset-modal').remove()"
class="w-full px-6 py-3 bg-green-500 text-white rounded-xl hover:bg-green-600 transition-colors font-medium">
Verstanden
</button>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
}
async impersonateUser(userId, userName) {
if (!confirm(`👤 Möchten Sie sich als "${userName}" anmelden?\n\nSie können jederzeit zur Admin-Ansicht zurückkehren.`)) {
return;
}
try {
// Impersonation-API implementieren falls gewünscht
this.showNotification('🚧 Impersonation-Feature wird implementiert...', 'info');
} catch (error) {
console.error('Fehler bei der Benutzer-Impersonation:', error);
this.showNotification('❌ Fehler bei der Benutzer-Impersonation', 'error');
}
}
editUser(userId) {
console.log(`✏️ Benutzer ${userId} wird bearbeitet`);
this.showUserModal(userId);