Rollen (Admin/Mitglied), Seite Kooperationen, Textanpassungen

- Gemeinsame Zugänge mit Rollen: Admin darf alles, Mitglied nutzt Kalender,
  Fahrtplaner, Treffpunkte und bearbeitet Mitglieder (kein Hinzufügen,
  Löschen, Import, keine Patches, keine Statistik-Korrektur)
- Server prüft die Rechte (403), Konten ohne Rolle gelten als Admin
- npm run user: add <name> [admin|mitglied], role <name> <rolle>
- Neue öffentliche Seite Kooperationen mit Titelbild, Anführer,
  Social-Media-Links und Beschreibung, Pflege durch Admin
- Kopfzeile bleibt bei mittlerer Breite einzeilig
- Texte auf Wunsch gekürzt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
guyg1474andClaude Opus 5.5 committed 2026-10-12 19:47:03 +02:00
1 parent f46016487d
commit 819219fb2d
18 files changed
+661 -106

No files matched your search

+31 -10
View File
@@ -1,12 +1,15 @@
// Benutzerverwaltung für den Login
//
// npm run user -- list
// npm run user -- add <name> Benutzer anlegen (Passwort wird abgefragt)
// npm run user -- passwd <name> Passwort ändern (meldet alle Sitzungen des Benutzers ab)
// npm run user -- remove <name> Benutzer löschen
// Die Konten sind gemeinsame Zugänge (z. B. "admin" und "hcrb" für alle Mitglieder), keine persönlichen.
//
// npm run user -- list alle Benutzer mit Rolle
// npm run user -- add <name> [admin|mitglied] Benutzer anlegen (Standard: mitglied, Passwort wird abgefragt)
// npm run user -- role <name> <admin|mitglied> Rolle ändern (meldet alle Sitzungen des Benutzers ab)
// npm run user -- passwd <name> Passwort ändern (meldet alle Sitzungen des Benutzers ab)
// npm run user -- remove <name> Benutzer löschen
import { createInterface } from 'node:readline';
import { hashPassword, readUsers, writeUsers, normalizeName, MIN_PASSWORD, USERS_FILE } from '../auth.js';
import { hashPassword, readUsers, writeUsers, normalizeName, MIN_PASSWORD, USERS_FILE, ROLES, roleOf } from '../auth.js';
// Passwort verdeckt einlesen (bei umgeleiteter Eingabe zeilenweise)
let pipedLines;
@@ -52,22 +55,40 @@ async function newPassword() {
return hashPassword(pw);
}
const [cmd, rawName] = process.argv.slice(2);
const [cmd, rawName, rawRole] = process.argv.slice(2);
const role = String(rawRole ?? '').trim().toLowerCase();
function checkRole(value) {
if (!ROLES.includes(value)) throw new Error(`Rolle muss ${ROLES.join(' oder ')} sein.`);
return value;
}
const name = normalizeName(rawName);
const users = readUsers();
const user = users.find((u) => u.name === name);
try {
if (cmd === 'list') {
console.log(users.length ? users.map((u) => u.name).join('\n') : 'Noch keine Benutzer angelegt.');
console.log(users.length
? users.map((u) => `${u.name.padEnd(20)} ${roleOf(u)}${u.role ? '' : ' (noch ohne Rolle gespeichert)'}`).join('\n')
: 'Noch keine Benutzer angelegt.');
} else if (cmd === 'add' && name) {
if (!/^[a-z0-9._-]{2,32}$/.test(name)) {
throw new Error('Benutzername: 2–32 Zeichen, nur a–z, 0–9, Punkt, Minus, Unterstrich.');
}
if (user) throw new Error(`Benutzer „${name}“ gibt es schon.`);
users.push({ name, hash: await newPassword(), changedAt: Date.now() });
const newRole = checkRole(role || 'mitglied');
users.push({ name, role: newRole, hash: await newPassword(), changedAt: Date.now() });
writeUsers(users);
console.log(`Benutzer „${name}“ angelegt.`);
console.log(`Benutzer „${name}“ als ${newRole} angelegt.`);
} else if (cmd === 'role' && name && role) {
if (!user) throw new Error(`Benutzer „${name}“ gibt es nicht.`);
user.role = checkRole(role);
if (user.role === 'mitglied' && !users.some((u) => roleOf(u) === 'admin')) {
throw new Error('Das ist der letzte Admin. Lege zuerst einen anderen Admin an.');
}
user.changedAt = Date.now();
writeUsers(users);
console.log(`„${name}“ ist jetzt ${user.role}. Bestehende Anmeldungen sind abgemeldet.`);
} else if (cmd === 'passwd' && name) {
if (!user) throw new Error(`Benutzer „${name}“ gibt es nicht.`);
user.hash = await newPassword();
@@ -79,7 +100,7 @@ try {
writeUsers(users.filter((u) => u !== user));
console.log(`Benutzer „${name}“ gelöscht.`);
} else {
console.log('Benutzung: npm run user -- list | add <name> | passwd <name> | remove <name>');
console.log('Benutzung: npm run user -- list | add <name> [admin|mitglied] | role <name> <admin|mitglied> | passwd <name> | remove <name>');
console.log(`Benutzerdatei: ${USERS_FILE}`);
process.exitCode = cmd ? 1 : 0;
}