Ein Konto liess sich anlegen und danach nie wieder ändern: kein Weg zum Administrator, keiner zurück, keiner zum Löschen. Mit Einladungslinks füllte sich der Server also in genau eine Richtung. **Warum es einen Besitzer braucht.** 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. Ein Konto, das ausgenommen ist, schliesst ihn aus. Es ist das erste, also das, mit dem eingerichtet wurde; die Migration trägt das auf bestehenden Servern nach, und weil die Kennungen zeitlich geordnet vergeben werden, ist der Älteste schlicht der mit der kleinsten. Weitergeben lässt er sich: vom Besitzer, an einen Administrator, mit Rückfrage. Nur an einen Administrator, sonst wäre der Server einen Klick von einem Besitzer entfernt, der die Verwaltung gar nicht sieht. **Drei Türen sind zugemauert**, und jede hat ihren Test: dem Besitzer das Recht nehmen, den Besitzer löschen, sich selbst das eigene Recht nehmen. Das letzte ist die unauffälligste — wer sich im Eifer entmachtet, steht vor einer Verwaltung, die er nicht mehr öffnen kann, und das Zurücknehmen braucht genau die. Gemessen und als Test festgehalten: ein frisch vergebenes Adminrecht gilt **sofort**, ohne neue Anmeldung. Die Rolle wird je Anfrage aus der Datenbank gelesen und nicht aus dem Token — ich hatte das Gegenteil befürchtet. Löschen nimmt mit, was am Konto hing: Geräte, Sehstände, Sehprotokoll, Meldungen, offene Einladungen. Alles hängt mit `Cascade` daran. Zahlen über jemanden zu führen, den es nicht mehr gibt, wäre die schlechtere Hälfte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
44 lines
1.4 KiB
C#
44 lines
1.4 KiB
C#
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
#nullable disable
|
|
|
|
namespace Flaro.Data.Migrations
|
|
{
|
|
/// <inheritdoc />
|
|
public partial class Besitzer : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
migrationBuilder.AddColumn<bool>(
|
|
name: "IsOwner",
|
|
table: "Users",
|
|
type: "INTEGER",
|
|
nullable: false,
|
|
defaultValue: false);
|
|
|
|
// **Der Älteste erbt.** Auf einem Server, den es schon gibt, ist
|
|
// der Besitzer das Konto, mit dem eingerichtet wurde — und das
|
|
// ist das mit der kleinsten Kennung, weil die zeitlich geordnet
|
|
// vergeben werden (`Guid.CreateVersion7`).
|
|
//
|
|
// Ohne diese Zeilen hätte ein bestehender Server gar keinen
|
|
// Besitzer, und das Adminrecht liesse sich bis zum letzten
|
|
// Administrator abräumen.
|
|
migrationBuilder.Sql(
|
|
"""
|
|
UPDATE Users SET IsOwner = 1
|
|
WHERE Id = (SELECT Id FROM Users ORDER BY Id LIMIT 1);
|
|
""");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
migrationBuilder.DropColumn(
|
|
name: "IsOwner",
|
|
table: "Users");
|
|
}
|
|
}
|
|
}
|