"""Chats verwalten: Titel, Umbenennen, Löschen.""" import re import pytest from sqlalchemy import func, select from app.audit.models import AuditEvent from app.chat.models import ChatSession, Message from app.tasks.models import TaskRun from app.tasks.worker import Worker from helpers import connect_repo, create_workspace @pytest.fixture def setup(browser, people, git_repo): anna = browser("anna") workspace_id = create_workspace(anna, people["team_demo"]) connect_repo(anna, workspace_id, git_repo) anna.post(f"/workspaces/{workspace_id}/members", {"username": "ben", "role": "member"}) anna.post(f"/workspaces/{workspace_id}/members", {"username": "clara", "role": "member"}) ben = browser("ben") chat_id = int(ben.post(f"/workspaces/{workspace_id}/chats").headers["location"].rsplit("/", 1)[1]) return {"anna": anna, "ben": ben, "clara": browser("clara"), "workspace_id": workspace_id, "chat_id": chat_id} def send(b, chat_id: int, text: str): response = b.post(f"/chats/{chat_id}/messages", {"content": text}, headers={"HX-Request": "true"}) assert response.status_code == 200, response.text def title(db, chat_id: int) -> str: with db.session() as session: return session.get(ChatSession, chat_id).title def test_erste_frage_wird_titel(setup, db, settings): send(setup["ben"], setup["chat_id"], "Wie ist der Timeout\nkonfiguriert? " + "x" * 80) assert title(db, setup["chat_id"]).startswith("Wie ist der Timeout konfiguriert? x") assert title(db, setup["chat_id"]).endswith("…") and len(title(db, setup["chat_id"])) == 61 Worker(db, settings).run_once() send(setup["ben"], setup["chat_id"], "Zweite Frage") assert not title(db, setup["chat_id"]).startswith("Zweite") def test_umbenennen(setup, db): assert setup["ben"].post(f"/chats/{setup['chat_id']}/rename", {"title": " Timeouts "}).status_code == 303 assert title(db, setup["chat_id"]) == "Timeouts" assert "Timeouts" in setup["ben"].get(f"/workspaces/{setup['workspace_id']}").text assert setup["ben"].post(f"/chats/{setup['chat_id']}/rename", {"title": " "}).status_code == 400 # Workspace-Admin darf, anderes Mitglied nicht assert setup["anna"].post(f"/chats/{setup['chat_id']}/rename", {"title": "Von Anna"}).status_code == 303 assert setup["clara"].post(f"/chats/{setup['chat_id']}/rename", {"title": "Clara"}).status_code == 403 assert "Bearbeiten" not in setup["clara"].get(f"/chats/{setup['chat_id']}").text assert title(db, setup["chat_id"]) == "Von Anna" def test_loeschen(setup, db, settings, browser): send(setup["ben"], setup["chat_id"], "Hallo") # Solange die Antwort läuft, nicht löschbar response = setup["ben"].post(f"/chats/{setup['chat_id']}/delete") assert response.status_code == 400 and "erst abbrechen" in response.text Worker(db, settings).run_once() assert setup["clara"].post(f"/chats/{setup['chat_id']}/delete").status_code == 403 assert browser("dora").post(f"/chats/{setup['chat_id']}/delete").status_code == 404 response = setup["ben"].post(f"/chats/{setup['chat_id']}/delete") assert response.status_code == 303 and response.headers["location"] == f"/workspaces/{setup['workspace_id']}" with db.session() as session: assert session.get(ChatSession, setup["chat_id"]) is None assert session.scalar(select(func.count()).select_from(Message)) == 0 assert session.scalar(select(func.count()).select_from(TaskRun)) == 0 assert session.scalar(select(AuditEvent).where(AuditEvent.action == "chat.deleted")) is not None assert setup["ben"].get(f"/chats/{setup['chat_id']}").status_code == 404 def test_workspace_admin_loescht_fremden_chat(setup, db): assert setup["anna"].post(f"/chats/{setup['chat_id']}/delete").status_code == 303 def test_loeschen_aus_der_workspace_uebersicht(setup): """Knopf in der Chat-Liste nur für Autor und Workspace-Admins.""" action = f'action="/chats/{setup["chat_id"]}/delete"' page = f"/workspaces/{setup['workspace_id']}" assert action in setup["ben"].get(page).text assert action in setup["anna"].get(page).text assert action not in setup["clara"].get(page).text def test_statische_dateien_mit_version(setup): """Nach einem Update lädt der Browser neue Skripte statt alter Kopien aus dem Cache.""" import re page = setup["ben"].get(f"/workspaces/{setup['workspace_id']}").text assert re.search(r'/static/js/app\.js\?v=[0-9a-f]+"', page) def test_rueckmeldung_nach_workspace_vorgabe(setup, db, people): from app.identity import Principal from app.tools import service as tools admin = Principal(user_id=people["anna"], username="anna", display_name="Anna", is_admin=True, team_ids=frozenset({people["team_demo"]})) with db.session() as session: tools.classify_suggested(session, admin) response = setup["anna"].post(f"/workspaces/{setup['workspace_id']}/tools/git_log", {"decision": ""}) assert response.headers["location"] == f"/workspaces/{setup['workspace_id']}/settings?tab=tools&tool=git_log" page = setup["anna"].get(response.headers["location"]).text assert re.search(r"Gespeichert: git_log ist jetzt erlaubt \(wie global\)", page) setup["anna"].post(f"/workspaces/{setup['workspace_id']}/tools/git_log", {"decision": "deny"}) page = setup["anna"].get(f"/workspaces/{setup['workspace_id']}/settings?tab=tools&tool=git_log").text assert "ist jetzt gesperrt (Vorgabe des Workspace)" in page