feat(admin): Bulk "alle Nutzerdaten löschen (Konten behalten)" + Nutzerliste alphabetisch
- DELETE /api/admin/user-data: loescht fuer ALLE Nutzer Verlauf, Statistik (usage/web_search_usage/cost_usage) und Erinnerungen; Konten bleiben. Gefahrenzone-Knopf mit doppelter Bestaetigung, audit-geloggt. - list_users jetzt ORDER BY LOWER(display_name) -> Nutzerkarten alphabetisch (ohne Gross-/Kleinschreibung). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8fb5e42e1b
commit
c337ea4309
4 changed files with 46 additions and 1 deletions
20
app/store.py
20
app/store.py
|
|
@ -156,6 +156,11 @@ class Store(ABC):
|
|||
def delete_user_memories(self, user_id: str) -> int:
|
||||
"""Loescht alle Erinnerungen eines Nutzers. Liefert die Zahl geloeschter Erinnerungen."""
|
||||
|
||||
@abstractmethod
|
||||
def wipe_all_user_data(self) -> dict:
|
||||
"""Loescht fuer ALLE Nutzer Verlauf, Statistik und Erinnerungen; Konten bleiben.
|
||||
Liefert ein Dict mit Anzahlen je Kategorie."""
|
||||
|
||||
@abstractmethod
|
||||
def reset_token(self, user_id: str) -> tuple[User, str] | None:
|
||||
"""Generiert einen neuen Token fuer den Nutzer; der alte wird sofort ungueltig.
|
||||
|
|
@ -354,7 +359,7 @@ class SQLiteStore(Store):
|
|||
def list_users(self) -> list[User]:
|
||||
with self._connect() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM users WHERE id != ? ORDER BY created_at",
|
||||
"SELECT * FROM users WHERE id != ? ORDER BY LOWER(display_name)",
|
||||
(ANONYMOUS_USER_ID,),
|
||||
).fetchall()
|
||||
return [self._row_to_user(row) for row in rows]
|
||||
|
|
@ -607,6 +612,19 @@ class SQLiteStore(Store):
|
|||
cur = conn.execute("DELETE FROM memories WHERE user_id = ?", (user_id,))
|
||||
return cur.rowcount
|
||||
|
||||
def wipe_all_user_data(self) -> dict:
|
||||
with self._connect() as conn:
|
||||
counts = {
|
||||
"messages": conn.execute("DELETE FROM messages").rowcount,
|
||||
"sessions": conn.execute("DELETE FROM sessions").rowcount,
|
||||
"memories": conn.execute("DELETE FROM memories").rowcount,
|
||||
}
|
||||
stats = 0
|
||||
for tbl in ("usage", "web_search_usage", "cost_usage"):
|
||||
stats += conn.execute(f"DELETE FROM {tbl}").rowcount
|
||||
counts["stats"] = stats
|
||||
return counts
|
||||
|
||||
def reset_token(self, user_id: str) -> tuple[User, str] | None:
|
||||
with self._connect() as conn:
|
||||
row = conn.execute("SELECT * FROM users WHERE id = ?", (user_id,)).fetchone()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue