51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""Team-Scoping (Mandantenfähigkeit).
|
||
|
||
Jeder Datensatz gehört zu genau einem Team; jede Abfrage filtert nach dem Team
|
||
des eingeloggten Nutzers (siehe CLAUDE.md). Das aktive Team wird beim Login in
|
||
die Session geschrieben und hier zentral ausgelesen.
|
||
|
||
Faustregel für alle Routen: NIE Model.query direkt verwenden, sondern
|
||
team_query(Model) — so kann keine Abfrage versehentlich Teamgrenzen überschreiten.
|
||
"""
|
||
|
||
from flask import session
|
||
|
||
SESSION_TEAM_KEY = "team_id"
|
||
SESSION_USER_KEY = "user_id"
|
||
|
||
|
||
def get_active_team_id():
|
||
"""team_id des aktiven Teams aus der Session (oder None)."""
|
||
return session.get(SESSION_TEAM_KEY)
|
||
|
||
|
||
def current_team():
|
||
"""Das aktive Team-Objekt (oder None), abgeleitet aus der Session."""
|
||
from .models import Team
|
||
|
||
team_id = get_active_team_id()
|
||
if team_id is None:
|
||
return None
|
||
return Team.query.get(team_id)
|
||
|
||
|
||
def team_query(model):
|
||
"""Query auf ein Modell, fest auf das aktive Team eingegrenzt.
|
||
|
||
Wirft ohne aktives Team bewusst, damit team-vergessende Aufrufe früh auffallen.
|
||
"""
|
||
team_id = get_active_team_id()
|
||
if team_id is None:
|
||
raise RuntimeError("Kein aktives Team in der Session – Login erforderlich.")
|
||
return model.query.filter_by(team_id=team_id)
|
||
|
||
|
||
def set_active_session(user_id, team_id):
|
||
"""Beim Login: Nutzer und sein Team in die Session schreiben."""
|
||
session[SESSION_USER_KEY] = user_id
|
||
session[SESSION_TEAM_KEY] = team_id
|
||
|
||
|
||
def clear_session():
|
||
"""Beim Logout: Session leeren."""
|
||
session.clear()
|