feat: quiz, cheat sheets, admin modules - MC quiz, search, user mgmt, content import
Dieser Commit ist enthalten in:
Ursprung
03778e4bed
Commit
3cd865ccbc
6 geänderte Dateien mit 425 neuen und 0 gelöschten Zeilen
86
edu/js/admin.js
Normale Datei
86
edu/js/admin.js
Normale Datei
|
|
@ -0,0 +1,86 @@
|
|||
'use strict';
|
||||
|
||||
var Admin = {
|
||||
render: function() {
|
||||
var el = document.getElementById('content');
|
||||
if (!App.currentUser || !App.currentUser.is_admin) {
|
||||
el.textContent = 'Kein Zugriff';
|
||||
return;
|
||||
}
|
||||
el.textContent = 'Lade Admin...';
|
||||
var self = this;
|
||||
API.get('/admin/users').then(function(data) { self.renderPanel(el, data.users); })
|
||||
.catch(function(e) { el.textContent = e.message; });
|
||||
},
|
||||
|
||||
renderPanel: function(el, users) {
|
||||
var h = '<div class="page-header"><h1>Administration</h1></div>';
|
||||
h += '<div class="admin-section"><h2>Benutzer</h2>';
|
||||
h += '<table class="user-table"><thead><tr><th>ID</th><th>Benutzer</th><th>Name</th><th>Admin</th><th>Erstellt</th><th></th></tr></thead><tbody>';
|
||||
users.forEach(function(u) {
|
||||
h += '<tr><td>' + u.id + '</td><td>' + Markdown.esc(u.username) + '</td><td>' + Markdown.esc(u.display_name) + '</td>';
|
||||
h += '<td>' + (u.is_admin ? 'Ja' : 'Nein') + '</td><td>' + new Date(u.created_at).toLocaleDateString('de-DE') + '</td>';
|
||||
h += '<td>' + (u.id !== App.currentUser.id ? '<button class="btn btn-small" data-del="' + u.id + '" data-name="' + Markdown.esc(u.username) + '">Entfernen</button>' : '') + '</td></tr>';
|
||||
});
|
||||
h += '</tbody></table>';
|
||||
h += '<h3 style="margin-top:24px;">Neuer Benutzer</h3>';
|
||||
h += '<form id="add-user-form" style="display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:end;">';
|
||||
h += '<div><label style="font-size:12px;color:var(--text-secondary)">Benutzername</label><br><input type="text" id="new-username" required style="width:140px"></div>';
|
||||
h += '<div><label style="font-size:12px;color:var(--text-secondary)">Anzeigename</label><br><input type="text" id="new-displayname" required style="width:140px"></div>';
|
||||
h += '<div><label style="font-size:12px;color:var(--text-secondary)">Passwort</label><br><input type="password" id="new-password" required style="width:140px"></div>';
|
||||
h += '<div><label style="font-size:12px;color:var(--text-secondary)"><input type="checkbox" id="new-is-admin"> Admin</label></div>';
|
||||
h += '<button type="submit" class="btn btn-primary">Erstellen</button></form>';
|
||||
h += '<div id="add-user-msg" style="margin-top:8px;"></div></div>';
|
||||
h += '<div class="admin-section"><h2>Content</h2>';
|
||||
h += '<p style="color:var(--text-secondary);margin-bottom:12px;">Markdown-Dateien neu einlesen und Datenbank aktualisieren.</p>';
|
||||
h += '<button class="btn btn-primary" id="import-btn">Content aktualisieren</button>';
|
||||
h += '<div id="import-msg" style="margin-top:8px;"></div></div>';
|
||||
el.innerHTML = h;
|
||||
|
||||
var self = this;
|
||||
el.querySelectorAll('[data-del]').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() { self.deleteUser(parseInt(btn.dataset.del), btn.dataset.name); });
|
||||
});
|
||||
document.getElementById('add-user-form').addEventListener('submit', function(e) { e.preventDefault(); self.addUser(); });
|
||||
document.getElementById('import-btn').addEventListener('click', function() { self.importContent(); });
|
||||
},
|
||||
|
||||
addUser: function() {
|
||||
var msg = document.getElementById('add-user-msg');
|
||||
var self = this;
|
||||
API.post('/admin/users', {
|
||||
username: document.getElementById('new-username').value.trim(),
|
||||
display_name: document.getElementById('new-displayname').value.trim(),
|
||||
password: document.getElementById('new-password').value,
|
||||
is_admin: document.getElementById('new-is-admin').checked
|
||||
}).then(function() {
|
||||
msg.textContent = 'Benutzer erstellt!';
|
||||
msg.style.color = 'var(--green)';
|
||||
self.render();
|
||||
}).catch(function(e) {
|
||||
msg.textContent = e.message;
|
||||
msg.style.color = 'var(--red)';
|
||||
});
|
||||
},
|
||||
|
||||
deleteUser: function(id, name) {
|
||||
if (!confirm('Benutzer "' + name + '" wirklich entfernen? Lernfortschritt geht verloren.')) return;
|
||||
var self = this;
|
||||
API.del('/admin/users/' + id).then(function() { self.render(); })
|
||||
.catch(function(e) { alert('Fehler: ' + e.message); });
|
||||
},
|
||||
|
||||
importContent: function() {
|
||||
var msg = document.getElementById('import-msg');
|
||||
msg.textContent = 'Importiere...';
|
||||
msg.style.color = 'var(--text-muted)';
|
||||
API.post('/admin/import').then(function(data) {
|
||||
var s = data.stats;
|
||||
msg.textContent = 'Fertig! ' + s.decks + ' Decks, ' + s.cards + ' Karten, ' + s.tutorials + ' Tutorials, ' + s.cheatsheets + ' Cheat Sheets importiert.';
|
||||
msg.style.color = 'var(--green)';
|
||||
}).catch(function(e) {
|
||||
msg.textContent = e.message;
|
||||
msg.style.color = 'var(--red)';
|
||||
});
|
||||
}
|
||||
};
|
||||
Laden …
Tabelle hinzufügen
Einen Link hinzufügen
In neuem Issue referenzieren