import { useState, useEffect } from 'react' import { useAuth } from '../contexts/AuthContext' import { usePermissions } from '../contexts/PermissionsContext' const Users = () => { const { authFetch } = useAuth() const { refreshPermissions } = usePermissions() const [users, setUsers] = useState([]) const [groups, setGroups] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState('') const [showForm, setShowForm] = useState(false) const [editingUser, setEditingUser] = useState(null) const [showDeleteModal, setShowDeleteModal] = useState(false) const [userToDelete, setUserToDelete] = useState(null) const [confirmChecked, setConfirmChecked] = useState(false) const [showToggleModal, setShowToggleModal] = useState(false) const [userToToggle, setUserToToggle] = useState(null) const [confirmToggleChecked, setConfirmToggleChecked] = useState(false) const [formData, setFormData] = useState({ username: '', email: '', oldPassword: '', password: '', confirmPassword: '', isAdmin: false, enabled: true, groupIds: [] }) const [showAdminWarning, setShowAdminWarning] = useState(false) useEffect(() => { fetchUsers() fetchGroups() }, []) const fetchUsers = async () => { try { setError('') const response = await authFetch('/api/users') if (response.ok) { const data = await response.json() setUsers(Array.isArray(data) ? data : []) } else { setError('Fehler beim Abrufen der Benutzer') } } catch (err) { setError('Fehler beim Abrufen der Benutzer') console.error('Error fetching users:', err) } } const fetchGroups = async () => { try { const response = await authFetch('/api/permission-groups') if (response.ok) { const data = await response.json() setGroups(Array.isArray(data) ? data : []) } } catch (err) { console.error('Error fetching permission groups:', err) } } const handleSubmit = async (e) => { e.preventDefault() setError('') setLoading(true) // Validierung: Passwort-Bestätigung muss übereinstimmen if (formData.password && formData.password !== formData.confirmPassword) { setError('Die Passwörter stimmen nicht überein') setLoading(false) return } // Validierung: Wenn Passwort geändert wird, muss altes Passwort vorhanden sein if (editingUser && formData.password && !formData.oldPassword) { setError('Bitte geben Sie das alte Passwort ein, um das Passwort zu ändern') setLoading(false) return } try { const url = editingUser ? `/api/users/${editingUser.id}` : '/api/users' const method = editingUser ? 'PUT' : 'POST' const body = editingUser ? { // Username/Email nur setzen wenn nicht der spezielle Admin-User mit UID 'admin' ...(formData.username && editingUser.id !== 'admin' && { username: formData.username }), ...(formData.email && editingUser.id !== 'admin' && { email: formData.email }), ...(formData.password && { password: formData.password, oldPassword: formData.oldPassword }), // isAdmin nur setzen wenn nicht UID 'admin' (UID 'admin' ist immer Admin) ...(formData.isAdmin !== undefined && editingUser.id !== 'admin' && { isAdmin: formData.isAdmin }), // enabled wird nicht über das Bearbeitungsformular geändert, nur über den Button in der Liste ...(formData.groupIds !== undefined && { groupIds: formData.groupIds }) } : { username: formData.username, email: formData.email, password: formData.password, isAdmin: formData.isAdmin || false, enabled: true, // Neue User sind immer aktiviert, enabled kann nur für UID 'admin' geändert werden groupIds: formData.groupIds || [] } const response = await authFetch(url, { method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), }) if (response.ok) { await fetchUsers() setFormData({ username: '', email: '', oldPassword: '', password: '', confirmPassword: '', isAdmin: false, enabled: true, groupIds: [] }) setShowForm(false) setEditingUser(null) setShowAdminWarning(false) // Aktualisiere Berechtigungen nach Änderung an Benutzern (Gruppen-Zuweisungen könnten sich geändert haben) refreshPermissions() } else { const errorData = await response.json() setError(errorData.error || 'Fehler beim Speichern des Benutzers') } } catch (err) { setError('Fehler beim Speichern des Benutzers') console.error('Error saving user:', err) } finally { setLoading(false) } } const handleEdit = (user) => { setEditingUser(user) setFormData({ username: user.username, email: user.email, oldPassword: '', password: '', confirmPassword: '', isAdmin: user.isAdmin || false, enabled: user.enabled !== undefined ? user.enabled : true, // Wird nicht im Formular angezeigt, nur für internen Zustand groupIds: user.groupIds || [] }) setShowForm(true) } const handleDelete = (user) => { setUserToDelete(user) setShowDeleteModal(true) setConfirmChecked(false) } const handleToggleEnabled = (user) => { if (user.id !== 'admin') { return } setUserToToggle(user) setShowToggleModal(true) setConfirmToggleChecked(false) } const confirmToggle = async () => { if (!confirmToggleChecked || !userToToggle) { return } const newEnabled = !userToToggle.enabled const action = newEnabled ? 'aktivieren' : 'deaktivieren' try { setLoading(true) const response = await authFetch(`/api/users/${userToToggle.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ enabled: newEnabled }), }) if (response.ok) { await fetchUsers() setShowToggleModal(false) setUserToToggle(null) setConfirmToggleChecked(false) // Aktualisiere Berechtigungen nach Änderung refreshPermissions() } else { const errorData = await response.json().catch(() => ({ error: `Fehler beim ${action}` })) const errorMessage = errorData.error || `Fehler beim ${action} des Admin-Users` setError(errorMessage) // Schließe Modal bei Fehler if (response.status === 403) { setShowToggleModal(false) setUserToToggle(null) setConfirmToggleChecked(false) } } } catch (err) { console.error(`Error toggling enabled for admin user:`, err) setError(`Fehler beim ${action} des Admin-Users`) } finally { setLoading(false) } } const cancelToggle = () => { setShowToggleModal(false) setUserToToggle(null) setConfirmToggleChecked(false) } const confirmDelete = async () => { if (!confirmChecked || !userToDelete) { return } try { const response = await authFetch(`/api/users/${userToDelete.id}`, { method: 'DELETE', }) if (response.ok) { await fetchUsers() setShowDeleteModal(false) setUserToDelete(null) setConfirmChecked(false) // Aktualisiere Berechtigungen nach Löschen eines Benutzers refreshPermissions() } else { const errorData = await response.json().catch(() => ({ error: 'Fehler beim Löschen' })) const errorMessage = errorData.error || 'Fehler beim Löschen des Benutzers' // Zeige Fehlermeldung setError(errorMessage) // Wenn Admin-Löschung verhindert wurde, schließe Modal if (response.status === 403) { setShowDeleteModal(false) setUserToDelete(null) setConfirmChecked(false) } } } catch (err) { console.error('Error deleting user:', err) setError('Fehler beim Löschen des Benutzers') } } const cancelDelete = () => { setShowDeleteModal(false) setUserToDelete(null) setConfirmChecked(false) } const handleChange = (e) => { setFormData({ ...formData, [e.target.name]: e.target.value }) } const handleGroupToggle = (groupId) => { setFormData(prev => { const groupIds = prev.groupIds || [] if (groupIds.includes(groupId)) { return { ...prev, groupIds: groupIds.filter(id => id !== groupId) } } else { return { ...prev, groupIds: [...groupIds, groupId] } } }) } const handleAdminToggle = (e) => { const isAdmin = e.target.checked if (isAdmin && !showAdminWarning) { setShowAdminWarning(true) } setFormData(prev => ({ ...prev, isAdmin, // Wenn Admin aktiviert wird, entferne alle Gruppen und stelle sicher dass enabled=true groupIds: isAdmin ? [] : prev.groupIds, enabled: isAdmin ? true : (prev.enabled !== undefined ? prev.enabled : true) // Admin muss immer enabled sein })) } const getPermissionLabel = (permission) => { switch (permission) { case 'READ': return 'Lesen' case 'READ_WRITE': return 'Lesen/Schreiben' case 'FULL_ACCESS': return 'Vollzugriff' default: return permission } } return (

Benutzerverwaltung

Verwalten Sie lokale Benutzer und deren Zugangsdaten.

{/* Create/Edit User Form */} {showForm && (

{editingUser ? 'Benutzer bearbeiten' : 'Neuen Benutzer erstellen'}

{editingUser && editingUser.id === 'admin' && (

Der Benutzername des Admin-Users mit UID 'admin' kann nicht geändert werden

)}
{editingUser && editingUser.id === 'admin' && (

Die E-Mail-Adresse des Admin-Users mit UID 'admin' kann nicht geändert werden

)}
{editingUser && (
)}
{/* Passwortrichtlinie - nur anzeigen wenn Passwort eingegeben wird */} {(formData.password || !editingUser) && (

Passwortrichtlinie:

  • = 8 ? 'text-green-400' : ''}`}> {formData.password.length >= 8 ? '✓' : '○'} Mindestens 8 Zeichen
  • {/[A-Z]/.test(formData.password) ? '✓' : '○'} Mindestens ein Großbuchstabe
  • {/[a-z]/.test(formData.password) ? '✓' : '○'} Mindestens ein Kleinbuchstabe
  • {/[0-9]/.test(formData.password) ? '✓' : '○'} Mindestens eine Zahl
  • {/[^A-Za-z0-9]/.test(formData.password) ? '✓' : '○'} Mindestens ein Sonderzeichen
)}
{formData.confirmPassword && formData.password !== formData.confirmPassword && (

Die Passwörter stimmen nicht überein

)} {formData.confirmPassword && formData.password === formData.confirmPassword && formData.password && (

✓ Passwörter stimmen überein

)}
{/* Admin Checkbox - nicht für UID 'admin' */} {(!editingUser || editingUser.id !== 'admin') && (
)} {/* Berechtigungsgruppen - ausgegraut wenn Admin oder UID 'admin' */}
{groups.length === 0 ? (

Keine Berechtigungsgruppen vorhanden

) : (
{groups.map(group => ( ))}
)}
{error && (
{error}
)}
)} {/* Users List */}

Benutzer

{error && !showForm && (

{error}

)} {users.length === 0 ? (

Noch keine Benutzer vorhanden. Erstellen Sie Ihren ersten Benutzer!

) : (
{users.map((user) => (

{user.username}

{user.isAdmin && ( ADMIN )} {user.id === 'admin' && user.enabled === false && ( DEAKTIVIERT )}

{user.email}

{!user.isAdmin && user.groupIds && user.groupIds.length > 0 && (

Berechtigungsgruppen:

{user.groupIds.map(groupId => { const group = groups.find(g => g.id === groupId) return group ? ( {group.name} ({getPermissionLabel(group.permission)}) ) : null })}
)}

Erstellt: {user.createdAt ? new Date(user.createdAt).toLocaleString('de-DE') : 'Unbekannt'}

{user.id && (

ID: {user.id}

)}
{user.id === 'admin' ? ( ) : ( )}
))}
)}
{/* Admin Warning Modal */} {showAdminWarning && (

Administrator-Berechtigung

Sie sind dabei, diesem Benutzer Administrator-Rechte zu gewähren.

⚠️ Mögliche Gefahren:

  • Vollständiger Zugriff auf alle Funktionen und Einstellungen
  • Möglichkeit, andere Benutzer zu erstellen, zu bearbeiten oder zu löschen
  • Zugriff auf alle Spaces, FQDNs und Zertifikate
  • Möglichkeit, Berechtigungsgruppen zu verwalten
  • Keine Einschränkungen durch Berechtigungsgruppen

Möchten Sie wirklich fortfahren?

)} {/* Delete Confirmation Modal */} {showDeleteModal && userToDelete && (

Benutzer löschen

Möchten Sie den Benutzer {userToDelete.username} wirklich löschen?

Diese Aktion kann nicht rückgängig gemacht werden.

)} {/* Toggle Enabled Confirmation Modal */} {showToggleModal && userToToggle && (
{userToToggle.enabled ? ( ) : ( )}

Admin-User {userToToggle.enabled ? 'deaktivieren' : 'aktivieren'}

Möchten Sie den Admin-User {userToToggle.username} (UID: {userToToggle.id}) wirklich {userToToggle.enabled ? 'deaktivieren' : 'aktivieren'}?

{userToToggle.enabled ? 'Der Admin-User kann sich nach der Deaktivierung nicht mehr anmelden und keine API-Calls durchführen.' : 'Der Admin-User kann sich nach der Aktivierung wieder anmelden und API-Calls durchführen.'}

)}
) } export default Users