Projekt-Sichtbarkeit: Nutzer-Zuordnung, projektbezogene Filterung und Schreibschutz
- Neues Modell ProjektUser (projekt_users) für projektbezogene Sichtbarkeit
- Migration V01_09 legt Tabelle an (keine Initial-Befüllung)
- CRUD-Logik für Projekt-User-Zuordnungen mit Cross-DB-User-Auflösung
- Serverseitige Sichtbarkeits-Filterung: Projekt-Liste/Get filtert nach
projekt_users-Zuordnung für Nicht-SysAdmin/Nicht-AppAdmin
- Auto-Assignment: Ersteller wird bei Projektanlage automatisch zugeordnet
- Sichtbarkeits-Filterung auf CallLog und Kontaktadresse erweitert
(Liste und Einzelabruf)
- Schreibschutz: Alle Schreib-Endpunkte (update/delete) für Projekt,
Kontaktadresse und CallLog prüfen Projekt-Zuordnung vor der Ausführung
- Hilfsfunktionen _get_visible_user_id() und _require_projekt_access()
zur Kapselung der wiederkehrenden Prüfungen
- REST-Endpunkte /xhr/projektuser/{list,add,remove};
Schreib-Endpunkte mit @authorisation_required([]) als Erweiterungspunkt
- Client: Neues Modell projekt_user.ts, Listen-Komponente mit Modal
(Select-Widget), Button in Projekt-Maske, Route registriert
- Build aktualisiert (tsc + rollup)
- AGENTS.md: Vorgaben für projektbezogene Sichtbarkeit dokumentiert
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
b2f8684afb
commit
4cb0084066
12 files changed
+758
-25
No files matched your search
@@ -10,31 +10,47 @@ dort über den Decorator authorisation_required.
|
||||
:version: 1.0
|
||||
"""
|
||||
from db import dbapp
|
||||
from crm.model import CallLog, Projekt
|
||||
from crm.model import CallLog, Projekt, ProjektUser
|
||||
|
||||
from auth.model.errors import ApplicationError, HtmlStatusCode
|
||||
|
||||
session = dbapp.session
|
||||
|
||||
|
||||
def get_call_logs(projekt_id: int | None = None):
|
||||
def get_call_logs(projekt_id: int | None = None, user_id: int | None = None):
|
||||
"""
|
||||
Liefert Gesprächsnotizen, sortiert nach Datum absteigend.
|
||||
|
||||
Ist projekt_id gesetzt, werden nur die Notizen dieses Projekts
|
||||
zurückgegeben (serverseitige Filterung). Ohne projekt_id werden
|
||||
alle Notizen geliefert.
|
||||
|
||||
Ist user_id gesetzt, werden nur Notizen von Projekten geliefert, denen
|
||||
der Nutzer über projekt_users zugeordnet ist (Sichtbarkeits-Filterung).
|
||||
SysAdmin und AppAdmin übergeben user_id=None und sehen alle Notizen.
|
||||
"""
|
||||
query = CallLog.query
|
||||
if projekt_id is not None:
|
||||
query = query.filter(CallLog.projekt_id == projekt_id)
|
||||
if user_id is not None:
|
||||
# Nur Notizen von Projekten, denen der Nutzer zugeordnet ist.
|
||||
query = query.filter(
|
||||
CallLog.projekt_id.in_(
|
||||
dbapp.session.query(ProjektUser.projekt_id).filter(
|
||||
ProjektUser.user_id == user_id
|
||||
)
|
||||
)
|
||||
)
|
||||
return query.order_by(CallLog.datum.desc()).all()
|
||||
|
||||
|
||||
def get_call_log(call_log_id: int) -> CallLog:
|
||||
def get_call_log(call_log_id: int, user_id: int | None = None) -> CallLog:
|
||||
"""
|
||||
Liefert eine einzelne Gesprächsnotiz anhand ihrer ID.
|
||||
Wirft ApplicationError (404), falls die Notiz nicht existiert.
|
||||
|
||||
Ist user_id gesetzt, wird zusätzlich geprüft, ob der Nutzer dem
|
||||
Projekt der Notiz zugeordnet ist; sonst wird 404 geliefert.
|
||||
"""
|
||||
call_log = CallLog.query.get(call_log_id)
|
||||
if call_log is None:
|
||||
@@ -42,6 +58,16 @@ def get_call_log(call_log_id: int) -> CallLog:
|
||||
"Gesprächsnotiz mit der ID {} wurde nicht gefunden.".format(call_log_id),
|
||||
htmlstatus=HtmlStatusCode.Not_Found,
|
||||
)
|
||||
if user_id is not None:
|
||||
zuordnung = ProjektUser.query.filter(
|
||||
ProjektUser.projekt_id == call_log.projekt_id,
|
||||
ProjektUser.user_id == user_id,
|
||||
).first()
|
||||
if zuordnung is None:
|
||||
raise ApplicationError(
|
||||
"Gesprächsnotiz mit der ID {} wurde nicht gefunden.".format(call_log_id),
|
||||
htmlstatus=HtmlStatusCode.Not_Found,
|
||||
)
|
||||
return call_log
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user