(`/users/${id}`, { method: 'DELETE' });
+
/* ---------- Einladungen ---------- */
export type Einladung = {
diff --git a/web/app/src/views/einstellungen/benutzer.ts b/web/app/src/views/einstellungen/benutzer.ts
index 6c2a220..da036ed 100644
--- a/web/app/src/views/einstellungen/benutzer.ts
+++ b/web/app/src/views/einstellungen/benutzer.ts
@@ -1,9 +1,10 @@
import {
- benutzer, benutzerAnlegen,
- einladungAnlegen, einladungen, einladungZurueckziehen, type Einladung,
+ benutzer, benutzerAnlegen, adminrechtSetzen, besitzUebergeben, benutzerLoeschen,
+ einladungAnlegen, einladungen, einladungZurueckziehen, sitzung,
+ type Einladung, type Rolle,
} from '../../api';
import { esc, knopf, fehlerzeile, meldung, hinweisZeigen } from '../../util';
-import { dialog } from '../../dialog';
+import { dialog, nachfragen } from '../../dialog';
import { abschnitt } from './teile';
@@ -96,6 +97,74 @@ export function benutzerbereich(): HTMLElement {
void laden();
+ /** Ein Konto mit dem, was man daran tun darf.
+ *
+ * **Der Besitzer ist ausgenommen.** Sobald Administratoren einander das
+ * Recht entziehen können, gibt es einen Zustand ohne jeden Administrator —
+ * und aus dem führt kein Weg zurück ausser dem an der Datenbank. Darum
+ * trägt ein Konto diese Marke, und an ihm sind beide Knöpfe aus. */
+ function kontozeile(b: Rolle): HTMLElement {
+ const d = document.createElement('div');
+ d.className = 'einstellung';
+
+ const ich = b.id === sitzung.wer?.id;
+ const rolle = b.isOwner ? 'Besitzer'
+ : b.isAdministrator ? 'Administrator' : 'Benutzer';
+
+ const text = document.createElement('div');
+ text.className = 'zeile';
+ text.style.flex = '1';
+ text.innerHTML = `${esc(b.userName)}${ich ? ' · das bist du' : ''}`
+ + `${esc(rolle)}`;
+
+ const reihe = document.createElement('div');
+ reihe.className = 'knopfreihe';
+ reihe.appendChild(text);
+
+ // **Dem Besitzer nimmt niemand etwas, und sich selbst auch nicht.** Wer
+ // sich im Eifer das eigene Recht nimmt, steht vor einer Verwaltung, die
+ // er nicht mehr öffnen kann — und das Zurücknehmen braucht genau die.
+ if (!b.isOwner && !(ich && b.isAdministrator)) {
+ const recht = knopf(b.isAdministrator ? 'Adminrecht nehmen' : 'Zum Administrator', 'btn');
+ recht.onclick = async () => {
+ recht.disabled = true;
+ try { await adminrechtSetzen(b.id, !b.isAdministrator); await laden(); }
+ catch (fehler) { recht.disabled = false; d.appendChild(fehlerzeile(meldung(fehler))); }
+ };
+ reihe.appendChild(recht);
+ }
+
+ // Weitergeben darf nur der Besitzer, und nur an einen Administrator.
+ if (sitzung.wer?.isOwner && !b.isOwner && b.isAdministrator) {
+ const uebergeben = knopf('Besitz übergeben', 'btn');
+ uebergeben.onclick = () => nachfragen({
+ titel: 'Besitz übergeben',
+ text: `„${b.userName}“ wird Besitzer dieses Servers. Dir nimmt dann `
+ + 'niemand mehr das Adminrecht ab — aber er kann es dir nehmen, '
+ + 'und zurückholen kannst du den Besitz nicht.',
+ bestaetigen: 'Übergeben',
+ tun: async () => { await besitzUebergeben(b.id); location.reload(); },
+ });
+ reihe.appendChild(uebergeben);
+ }
+
+ if (!b.isOwner && !ich) {
+ const weg = knopf('Löschen', 'btn btn-gefahr');
+ weg.onclick = () => nachfragen({
+ titel: `„${b.userName}“ löschen`,
+ text: 'Das Konto und alles, was daran hängt: Geräte, Sehstände, das '
+ + 'Sehprotokoll, Meldungen und offene Einladungen. Das lässt sich '
+ + 'nicht zurückholen.',
+ bestaetigen: 'Löschen',
+ tun: async () => { await benutzerLoeschen(b.id); await laden(); },
+ });
+ reihe.appendChild(weg);
+ }
+
+ d.appendChild(reihe);
+ return d;
+ }
+
/** Der fertige Link, genau einmal.
*
* **Die Adresse baut der Client.** Der Server weiss nicht, unter welchem
@@ -173,13 +242,7 @@ export function benutzerbereich(): HTMLElement {
try {
const alle = await benutzer();
liste.innerHTML = '';
- alle.forEach(b => {
- const d = document.createElement('div');
- d.className = 'einstellung';
- d.innerHTML = `${esc(b.userName)}`
- + `${b.isAdministrator ? 'Administrator' : 'Benutzer'}
`;
- liste.appendChild(d);
- });
+ alle.forEach(b => liste.appendChild(kontozeile(b)));
} catch (fehler) {
liste.innerHTML = '';
liste.appendChild(fehlerzeile(meldung(fehler)));