feat: Login-Name vs. Anzeigename (Server)

- Neue Spalte users.display_name (Original-Schreibweise); username bleibt der
  lowercase Login-Name. Setup/Create setzen display_name aus der Eingabe.
- Login bleibt case-insensitive (Anzeigename eingeben funktioniert -> wird
  lowercased -> trifft den Login-Namen).
- Profil: PUT /api/profile/ kann display_name UND username (Login-Name) aendern;
  bei Login-Namen-Wechsel kommt ein frischer Token zurueck (JWT sub haengt am
  Namen). Stabile interne ID (Integer-PK) traegt alle Verweise -> Umbenennen
  bricht Shares/Gruppen/creator_id nicht.
- display_name ueberall ausgeliefert/genutzt (me, profile, users, directory,
  shares, Gruppen-Mitglieder, creator/owner, ORGANIZER-Export).
- Migration + Backfill (display_name = username). Tests ergaenzt (17 gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-05-31 17:40:38 +02:00
parent 28a7cbe94e
commit f9923b022e
10 changed files with 103 additions and 15 deletions

View File

@@ -7,7 +7,10 @@ class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
# Login name: always lowercase, unique, used for authentication.
username = Column(String(50), unique=True, nullable=False)
# Human-facing name with original casing; editable. Falls back to username.
display_name = Column(String(100), nullable=True)
email = Column(String(100), unique=True, nullable=True)
password_hash = Column(String(255), nullable=False)
is_admin = Column(Boolean, default=False)
@@ -35,9 +38,9 @@ class User(Base):
)
@property
def display_name(self) -> str:
"""No dedicated display-name column exists — fall back to the username."""
return self.username
def display(self) -> str:
"""The name to show users: display_name if set, else the login name."""
return self.display_name or self.username
class CalDAVAccount(Base):