diff --git a/espid2sensor/public/global.js b/espid2sensor/public/global.js
index 096abf0..6a06aac 100644
--- a/espid2sensor/public/global.js
+++ b/espid2sensor/public/global.js
@@ -34,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => {
const data = await res.json();
if (data.success) {
userResult.textContent = 'User erfolgreich angelegt!';
+ if (window.loadUsers) window.loadUsers();
} else {
userResult.textContent = data.error || 'Fehler beim Anlegen.';
}
@@ -77,34 +78,6 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
- const resetPasswordBtn = document.getElementById('resetPasswordBtn');
- if (resetPasswordBtn) {
- resetPasswordBtn.addEventListener('click', async () => {
- const email = document.getElementById('resetEmail').value.trim();
- const newPassword = document.getElementById('resetNewPassword').value;
- const resetPasswordResult = document.getElementById('resetPasswordResult');
- if (!email || !newPassword) {
- resetPasswordResult.textContent = 'Email und neues Passwort erforderlich.';
- return;
- }
- try {
- const res = await fetch('/api/resetPassword', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ email, newPassword })
- });
- const data = await res.json();
- if (data.success) {
- resetPasswordResult.textContent = 'Passwort erfolgreich zurückgesetzt!';
- document.getElementById('resetPasswordForm').reset();
- } else {
- resetPasswordResult.textContent = data.error || 'Fehler beim Zurücksetzen.';
- }
- } catch (err) {
- resetPasswordResult.textContent = 'Serverfehler.';
- }
- });
- }
});
function updateSortArrows() {
@@ -467,6 +440,73 @@ function showModal(message, showCancelButton, callback) {
});
}
+ async function loadUsers() {
+ const usersTableBody = document.querySelector('#usersTable tbody');
+ const usersResult = document.getElementById('usersResult');
+ if (!usersTableBody) return;
+ try {
+ const res = await fetch('/api/users');
+ const users = await res.json();
+ usersTableBody.innerHTML = '';
+ users.forEach(u => {
+ const tr = document.createElement('tr');
+ tr.innerHTML = `
+
${u.email} |
+ ${u.role} |
+
+
+
+
+
+ |
+ `;
+ usersTableBody.appendChild(tr);
+ });
+
+ document.querySelectorAll('.resetUserBtn').forEach(btn => {
+ btn.addEventListener('click', async () => {
+ const email = btn.getAttribute('data-email');
+ const newPassword = prompt(`Neues Passwort für ${email}:`);
+ if (!newPassword) return;
+ try {
+ const res = await fetch('/api/resetPassword', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ email, newPassword })
+ });
+ const data = await res.json();
+ usersResult.textContent = data.success ? `Passwort für ${email} zurückgesetzt.` : (data.error || 'Fehler beim Zurücksetzen.');
+ } catch (err) {
+ usersResult.textContent = 'Serverfehler.';
+ }
+ });
+ });
+
+ document.querySelectorAll('.deleteUserBtn').forEach(btn => {
+ btn.addEventListener('click', () => {
+ const id = btn.getAttribute('data-id');
+ showModal('User wirklich löschen?', true, async (confirmed) => {
+ if (!confirmed) return;
+ try {
+ const res = await fetch(`/api/users/${id}`, { method: 'DELETE' });
+ const data = await res.json();
+ if (data.success) {
+ usersResult.textContent = 'User gelöscht.';
+ await loadUsers();
+ } else {
+ usersResult.textContent = data.error || 'Fehler beim Löschen.';
+ }
+ } catch (err) {
+ usersResult.textContent = 'Serverfehler.';
+ }
+ });
+ });
+ });
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
saveBtn.addEventListener('click', saveEntry);
refreshBtn.addEventListener('click', loadEntries);
cancelBtn.addEventListener('click', () => clearForm(true));
@@ -475,9 +515,10 @@ function showModal(message, showCancelButton, callback) {
tabInput.addEventListener('click', () => showTab('input'))
tabList.addEventListener('click', () => showTab('list'))
const tabUser = document.getElementById('tabUser');
- if (tabUser) tabUser.addEventListener('click', () => showTab('user'))
+ if (tabUser) tabUser.addEventListener('click', () => { showTab('user'); loadUsers(); })
loadEntries();
+ window.loadUsers = loadUsers;
});
window.showTab = showTab;
\ No newline at end of file
diff --git a/espid2sensor/routes/api.js b/espid2sensor/routes/api.js
index 2f2af8c..96f5bf8 100644
--- a/espid2sensor/routes/api.js
+++ b/espid2sensor/routes/api.js
@@ -127,4 +127,29 @@ export function registerApiRoutes(app, requireLogin) {
res.status(500).json({ error: 'Fehler beim Zurücksetzen' });
}
});
+
+ app.get('/api/users', requireLogin, async (req, res) => {
+ if (!req.session.isAdmin) return res.status(403).json({ error: 'Nur Admins erlaubt' });
+ try {
+ const users = await usersCollection.find({}, { projection: { email: 1, role: 1 } }).sort({ email: 1 }).toArray();
+ res.json(users);
+ } catch (err) {
+ res.status(500).json({ error: 'Fehler beim Laden der User' });
+ }
+ });
+
+ app.delete('/api/users/:id', requireLogin, async (req, res) => {
+ if (!req.session.isAdmin) return res.status(403).json({ error: 'Nur Admins erlaubt' });
+ const { id } = req.params;
+ if (id === String(req.session.userId)) {
+ return res.status(400).json({ error: 'Der eigene Account kann nicht gelöscht werden' });
+ }
+ try {
+ const result = await usersCollection.deleteOne({ _id: new ObjectId(id) });
+ if (result.deletedCount === 0) return res.status(404).json({ error: 'User nicht gefunden' });
+ res.json({ success: true });
+ } catch (err) {
+ res.status(500).json({ error: 'Fehler beim Löschen' });
+ }
+ });
}
diff --git a/espid2sensor/views/index.pug b/espid2sensor/views/index.pug
index 4c76f61..b628807 100644
--- a/espid2sensor/views/index.pug
+++ b/espid2sensor/views/index.pug
@@ -103,15 +103,15 @@ html(lang="de")
button#userCancelBtn(type="button") Abbrechen
div#userResult
div.card
- h2 Passwort eines Users zurücksetzen
- form#resetPasswordForm
- label(for="resetEmail") Email:
- input#resetEmail(type="email" required)
- label(for="resetNewPassword") Neues Passwort:
- input#resetNewPassword(type="password" required)
- .twobuttons
- button#resetPasswordBtn(type="button") Zurücksetzen
- div#resetPasswordResult
+ h2 Angemeldete User
+ table#usersTable
+ thead
+ tr
+ th Email
+ th Rolle
+ th Aktionen
+ tbody
+ div#usersResult
#version Version: #{version} vom #{vdate}
script(type="module" src="/global.js")
\ No newline at end of file