-- Migration 0017: persoenliche Gruppen als rechteerhaltende Migration weg -- von Direktvergaben (user_hostgroup_roles) -- Teil D.6 Schritt 3, D.4 -- (Umsetzungsauftrag_Sonnet5.md). Empfohlener Ansatz dort: "automatisch -- erzeugte persoenliche Gruppe je betroffenem Benutzer, danach manuelle -- Konsolidierung" -- niemand verliert oder gewinnt beim Umstieg etwas. -- -- user_hostgroup_roles bleibt nach dieser Migration bestehen (Projekt- -- konvention: Altes bleibt lesbar erhalten statt geloescht, siehe 0010/0012) -- und wird auch weiterhin von app/rbac.py ausgewertet -- das Leeren/ -- Umbenennen dieser Tabelle ist D.6 Schritt 5 (Schreibpfade abschalten), -- NICHT dieser Schritt. Diese Migration fuegt nur die Gruppen-Spiegelung -- HINZU, sie nimmt niemandem etwas weg. -- D.7-Risiko "Rechteausweitung ueber persoenliche Gruppen": Kennzeichen -- "persoenlich" (fuer UI/Reports in Schritt 6) plus Trigger-Sperre "max. 1 -- Mitglied" weiter unten. ADD COLUMN mit konstantem Default ist in SQLite -- ohne Tabellen-Rebuild moeglich. ALTER TABLE user_groups ADD COLUMN is_personal INTEGER NOT NULL DEFAULT 0; CREATE TRIGGER IF NOT EXISTS enforce_personal_group_single_member BEFORE INSERT ON user_group_members FOR EACH ROW WHEN (SELECT is_personal FROM user_groups WHERE id = NEW.user_group_id) = 1 AND (SELECT COUNT(*) FROM user_group_members WHERE user_group_id = NEW.user_group_id) >= 1 BEGIN SELECT RAISE(ABORT, 'Persoenliche Gruppe darf nur ein Mitglied haben'); END; -- Eine persoenliche Gruppe je Benutzer mit mindestens einer Direktvergabe. -- Name enthaelt bewusst die User-ID (nicht nur den Benutzernamen), um jede -- Kollision mit einer bereits existierenden, gleichnamigen Gruppe -- auszuschliessen (user_groups.name ist UNIQUE NOT NULL) -- ein Fehlschlag -- hier wuerde die gesamte Migration abbrechen. Explizite Transaktion fuer -- Atomaritaet (alle drei INSERTs oder keiner) -- anders als 0014 wird hier -- nichts umgebaut/gedroppt, PRAGMA foreign_keys = OFF ist daher nicht noetig -- (keine der drei INSERT-Anweisungen kann eine gueltige Fremdschluessel- -- Referenz verletzen). BEGIN IMMEDIATE; INSERT INTO user_groups (name, description, is_personal) SELECT 'Persoenlich: ' || u.username || ' (#' || u.id || ')', 'Automatisch erzeugt bei der Migration auf ausschliesslich ' || 'gruppenbasierte Berechtigungen (Teil D.6 Schritt 3, Migration ' || '0017) -- Spiegel der vormaligen Direktvergaben dieses Benutzers ' || 'aus user_hostgroup_roles. Kann spaeter bewusst in eine echte ' || 'Team-Gruppe ueberfuehrt werden (D.6 Schritt 6).', 1 FROM users u WHERE u.id IN (SELECT DISTINCT user_id FROM user_hostgroup_roles) AND u.deleted_at IS NULL; INSERT INTO user_group_members (user_group_id, user_id, added_by, added_at) SELECT ug.id, u.id, NULL, strftime('%Y-%m-%dT%H:%M:%fZ','now') FROM user_groups ug JOIN users u ON ug.name = 'Persoenlich: ' || u.username || ' (#' || u.id || ')' WHERE ug.is_personal = 1; INSERT INTO group_hostgroup_roles (user_group_id, host_group_id, role_id, granted_by, granted_at, expires_at) SELECT ug.id, uhr.host_group_id, uhr.role_id, uhr.granted_by, uhr.granted_at, uhr.expires_at FROM user_hostgroup_roles uhr JOIN users u ON u.id = uhr.user_id JOIN user_groups ug ON ug.name = 'Persoenlich: ' || u.username || ' (#' || u.id || ')' AND ug.is_personal = 1; COMMIT;