349 lines
16 KiB
Plaintext
349 lines
16 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Admin - Stundenerfassung</title>
|
|
<link rel="stylesheet" href="/css/style.css">
|
|
</head>
|
|
<body>
|
|
<div class="navbar">
|
|
<div class="container">
|
|
<h1>Stundenerfassung - Admin</h1>
|
|
<div class="nav-right">
|
|
<span>Admin: <%= user.firstname %> <%= user.lastname %></span>
|
|
<% if (user.roles && user.roles.length > 1) { %>
|
|
<select id="roleSwitcher" class="role-switcher" style="margin-right: 10px; padding: 5px 10px; border-radius: 4px; border: 1px solid #ddd;">
|
|
<% const roleLabels = { 'mitarbeiter': 'Mitarbeiter', 'verwaltung': 'Verwaltung', 'admin': 'Administrator' }; %>
|
|
<% user.roles.forEach(function(role) { %>
|
|
<option value="<%= role %>" <%= user.currentRole === role ? 'selected' : '' %>><%= roleLabels[role] || role %></option>
|
|
<% }); %>
|
|
</select>
|
|
<% } %>
|
|
<a href="/logout" class="btn btn-secondary">Abmelden</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<div class="admin-panel">
|
|
<h2>Benutzerverwaltung</h2>
|
|
|
|
<div class="add-user-form">
|
|
<h3>Neuen Benutzer anlegen</h3>
|
|
<form id="addUserForm">
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="firstname">Vorname</label>
|
|
<input type="text" id="firstname" name="firstname" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="lastname">Nachname</label>
|
|
<input type="text" id="lastname" name="lastname" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="username">Benutzername</label>
|
|
<input type="text" id="username" name="username" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="password">Passwort</label>
|
|
<input type="password" id="password" name="password" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Rollen</label>
|
|
<div class="roles-checkbox-group">
|
|
<label class="role-checkbox-label">
|
|
<input type="checkbox" name="roles" value="mitarbeiter" class="role-checkbox-input">
|
|
<span class="role-checkbox-text">Mitarbeiter</span>
|
|
</label>
|
|
<label class="role-checkbox-label">
|
|
<input type="checkbox" name="roles" value="verwaltung" class="role-checkbox-input">
|
|
<span class="role-checkbox-text">Verwaltung</span>
|
|
</label>
|
|
<label class="role-checkbox-label">
|
|
<input type="checkbox" name="roles" value="admin" class="role-checkbox-input">
|
|
<span class="role-checkbox-text">Administrator</span>
|
|
</label>
|
|
</div>
|
|
<small class="form-help-text">Wählen Sie eine oder mehrere Rollen aus</small>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="personalnummer">Personalnummer</label>
|
|
<input type="text" id="personalnummer" name="personalnummer">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="wochenstunden">Wochenstunden</label>
|
|
<input type="number" id="wochenstunden" name="wochenstunden" step="0.5" min="0" placeholder="z.B. 40">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="urlaubstage">Urlaubstage</label>
|
|
<input type="number" id="urlaubstage" name="urlaubstage" step="0.5" min="0" placeholder="z.B. 25">
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary">Benutzer anlegen</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="user-list">
|
|
<h3>Benutzer-Liste</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Benutzername</th>
|
|
<th>Vorname</th>
|
|
<th>Nachname</th>
|
|
<th>Rolle</th>
|
|
<th>Personalnummer</th>
|
|
<th>Wochenstunden</th>
|
|
<th>Urlaubstage</th>
|
|
<th>Erstellt am</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% users.forEach(function(u) { %>
|
|
<tr data-user-id="<%= u.id %>">
|
|
<td><%= u.id %></td>
|
|
<td><%= u.username %></td>
|
|
<td><%= u.firstname %></td>
|
|
<td><%= u.lastname %></td>
|
|
<td>
|
|
<div class="user-field-display" data-field="roles">
|
|
<%
|
|
const roleLabels = { 'mitarbeiter': 'Mitarbeiter', 'verwaltung': 'Verwaltung', 'admin': 'Admin' };
|
|
const userRoles = u.roles || [];
|
|
if (userRoles.length > 0) {
|
|
userRoles.forEach(function(role, idx) { %>
|
|
<span class="role-badge role-<%= role %>" style="margin-right: 5px;"><%= roleLabels[role] || role %></span>
|
|
<% });
|
|
} else {
|
|
%>
|
|
<span class="role-badge role-mitarbeiter">Mitarbeiter</span>
|
|
<% } %>
|
|
</div>
|
|
<div class="user-field-edit" data-field="roles" data-user-id="<%= u.id %>" style="display: none;">
|
|
<div class="roles-checkbox-group roles-checkbox-group-inline">
|
|
<label class="role-checkbox-label role-checkbox-label-small">
|
|
<input type="checkbox" class="role-checkbox role-checkbox-input" data-role="mitarbeiter" value="mitarbeiter" <%= userRoles.includes('mitarbeiter') ? 'checked' : '' %>>
|
|
<span class="role-checkbox-text">Mitarbeiter</span>
|
|
</label>
|
|
<label class="role-checkbox-label role-checkbox-label-small">
|
|
<input type="checkbox" class="role-checkbox role-checkbox-input" data-role="verwaltung" value="verwaltung" <%= userRoles.includes('verwaltung') ? 'checked' : '' %>>
|
|
<span class="role-checkbox-text">Verwaltung</span>
|
|
</label>
|
|
<label class="role-checkbox-label role-checkbox-label-small">
|
|
<input type="checkbox" class="role-checkbox role-checkbox-input" data-role="admin" value="admin" <%= userRoles.includes('admin') ? 'checked' : '' %>>
|
|
<span class="role-checkbox-text">Admin</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="user-field-display" data-field="personalnummer"><%= u.personalnummer || '-' %></span>
|
|
<input type="text" class="user-field-edit" data-field="personalnummer" data-user-id="<%= u.id %>" value="<%= u.personalnummer || '' %>" style="display: none; width: 100px;">
|
|
</td>
|
|
<td>
|
|
<span class="user-field-display" data-field="wochenstunden"><%= u.wochenstunden || '-' %></span>
|
|
<input type="number" step="0.5" class="user-field-edit" data-field="wochenstunden" data-user-id="<%= u.id %>" value="<%= u.wochenstunden || '' %>" style="display: none; width: 80px;">
|
|
</td>
|
|
<td>
|
|
<span class="user-field-display" data-field="urlaubstage"><%= u.urlaubstage || '-' %></span>
|
|
<input type="number" step="0.5" class="user-field-edit" data-field="urlaubstage" data-user-id="<%= u.id %>" value="<%= u.urlaubstage || '' %>" style="display: none; width: 80px;">
|
|
</td>
|
|
<td><%= new Date(u.created_at).toLocaleDateString('de-DE') %></td>
|
|
<td>
|
|
<button onclick="editUser(<%= u.id %>)" class="btn btn-primary btn-sm edit-user-btn" data-user-id="<%= u.id %>">Bearbeiten</button>
|
|
<button onclick="saveUser(<%= u.id %>)" class="btn btn-success btn-sm save-user-btn" data-user-id="<%= u.id %>" style="display: none;">Speichern</button>
|
|
<button onclick="cancelEditUser(<%= u.id %>)" class="btn btn-secondary btn-sm cancel-user-btn" data-user-id="<%= u.id %>" style="display: none;">Abbrechen</button>
|
|
<% if (u.id > 2) { %>
|
|
<button onclick="deleteUser(<%= u.id %>, '<%= u.username %>')" class="btn btn-danger btn-sm">Löschen</button>
|
|
<% } else { %>
|
|
<span class="text-muted">System</span>
|
|
<% } %>
|
|
</td>
|
|
</tr>
|
|
<% }); %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="ldap-sync-section" style="margin-top: 40px;">
|
|
<h2>LDAP-Synchronisation</h2>
|
|
|
|
<div class="ldap-config-form">
|
|
<h3>LDAP-Konfiguration</h3>
|
|
<form id="ldapConfigForm">
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" id="ldapEnabled" name="enabled">
|
|
LDAP-Synchronisation aktivieren
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="ldapUrl">LDAP-Server URL</label>
|
|
<input type="text" id="ldapUrl" name="url" placeholder="ldap://ldap.example.com:389">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ldapBaseDn">Base DN</label>
|
|
<input type="text" id="ldapBaseDn" name="base_dn" placeholder="dc=example,dc=com">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="ldapBindDn">Bind DN (optional)</label>
|
|
<input type="text" id="ldapBindDn" name="bind_dn" placeholder="cn=admin,dc=example,dc=com">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ldapBindPassword">Bind Passwort (optional)</label>
|
|
<input type="password" id="ldapBindPassword" name="bind_password" placeholder="Leer lassen um nicht zu ändern">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ldapSearchFilter">User Search Filter</label>
|
|
<input type="text" id="ldapSearchFilter" name="user_search_filter" placeholder="(objectClass=person)" value="(objectClass=person)">
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="ldapUsernameAttr">Username-Attribut</label>
|
|
<input type="text" id="ldapUsernameAttr" name="username_attribute" placeholder="cn" value="cn">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ldapFirstnameAttr">Vorname-Attribut</label>
|
|
<input type="text" id="ldapFirstnameAttr" name="firstname_attribute" placeholder="givenName" value="givenName">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ldapLastnameAttr">Nachname-Attribut</label>
|
|
<input type="text" id="ldapLastnameAttr" name="lastname_attribute" placeholder="sn" value="sn">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ldapSyncInterval">Sync-Intervall (Minuten)</label>
|
|
<input type="number" id="ldapSyncInterval" name="sync_interval" min="0" value="0" placeholder="0 = nur manuell">
|
|
<small>0 = nur manuelle Synchronisation</small>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary">Konfiguration speichern</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="ldap-sync-actions" style="margin-top: 30px;">
|
|
<h3>Synchronisation</h3>
|
|
<div style="margin-bottom: 15px;">
|
|
<button id="syncNowBtn" class="btn btn-primary">Synchronisation jetzt starten</button>
|
|
<span id="syncStatus" style="margin-left: 15px;"></span>
|
|
</div>
|
|
|
|
<% if (ldapConfig && ldapConfig.last_sync) { %>
|
|
<p><strong>Letzte Synchronisation:</strong> <%= new Date(ldapConfig.last_sync).toLocaleString('de-DE') %></p>
|
|
<% } else { %>
|
|
<p><strong>Letzte Synchronisation:</strong> Noch keine Synchronisation durchgeführt</p>
|
|
<% } %>
|
|
</div>
|
|
|
|
<div class="ldap-sync-log" style="margin-top: 30px;">
|
|
<h3>Sync-Log (letzte 10 Einträge)</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Zeitpunkt</th>
|
|
<th>Typ</th>
|
|
<th>Status</th>
|
|
<th>Benutzer synchronisiert</th>
|
|
<th>Fehlermeldung</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% if (syncLogs && syncLogs.length > 0) { %>
|
|
<% syncLogs.forEach(function(log) { %>
|
|
<tr>
|
|
<td><%= new Date(log.sync_started_at).toLocaleString('de-DE') %></td>
|
|
<td><%= log.sync_type === 'manual' ? 'Manuell' : 'Automatisch' %></td>
|
|
<td>
|
|
<span class="role-badge role-<%= log.status === 'success' ? 'mitarbeiter' : 'admin' %>">
|
|
<%= log.status === 'success' ? 'Erfolg' : 'Fehler' %>
|
|
</span>
|
|
</td>
|
|
<td><%= log.users_synced %></td>
|
|
<td><%= log.error_message || '-' %></td>
|
|
</tr>
|
|
<% }); %>
|
|
<% } else { %>
|
|
<tr>
|
|
<td colspan="5" style="text-align: center;">Keine Log-Einträge vorhanden</td>
|
|
</tr>
|
|
<% } %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/js/admin.js"></script>
|
|
<script>
|
|
// Rollenwechsel-Handler
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const roleSwitcher = document.getElementById('roleSwitcher');
|
|
if (roleSwitcher) {
|
|
roleSwitcher.addEventListener('change', async function() {
|
|
const newRole = this.value;
|
|
try {
|
|
const response = await fetch('/api/user/switch-role', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ role: newRole })
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.success) {
|
|
// Redirect basierend auf neuer Rolle
|
|
if (newRole === 'admin') {
|
|
window.location.href = '/admin';
|
|
} else if (newRole === 'verwaltung') {
|
|
window.location.href = '/verwaltung';
|
|
} else {
|
|
window.location.href = '/dashboard';
|
|
}
|
|
} else {
|
|
alert('Fehler beim Wechseln der Rolle: ' + (result.error || 'Unbekannter Fehler'));
|
|
// Wert zurücksetzen
|
|
this.value = '<%= user.currentRole || "admin" %>';
|
|
}
|
|
} catch (error) {
|
|
console.error('Fehler beim Rollenwechsel:', error);
|
|
alert('Fehler beim Wechseln der Rolle');
|
|
// Wert zurücksetzen
|
|
this.value = '<%= user.currentRole || "admin" %>';
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|