BERLIN = {"geonameId": 2950159, "name": "Berlin", "country": "DE", "lat": 52.52, "lon": 13.41, "population": 3426354, "capital": True} LEIDEN = {"geonameId": 2751773, "name": "Leiden", "country": "NL", "lat": 52.16, "lon": 4.49} def test_staedte_anderer_nur_lesend(login): anna, ben = login("anna"), login("ben") anna.post("/api/reisen/staedte", json=BERLIN) data = ben.get("/api/reisen").json() assert data["cities"] == [] assert [(p["name"], [c["name"] for c in p["cities"]]) for p in data["others"]] == [("Anna", ["Berlin"])] city_id = data["others"][0]["cities"][0]["id"] assert ben.delete(f"/api/reisen/staedte/{city_id}").status_code == 404 assert anna.get("/api/reisen").json()["others"] == [] def test_hauptstadt_kennzeichen(login): anna = login("anna") anna.post("/api/reisen/staedte", json=BERLIN) data = anna.post("/api/reisen/staedte", json=LEIDEN).json() # Mit Angabe aus der Suche gespeichert, ohne Angabe "unbekannt" (wird im Hintergrund nachgetragen) assert {c["name"]: c["capital"] for c in data["cities"]} == {"Berlin": True, "Leiden": None} def test_doppelte_stadt_wird_ignoriert(login): anna = login("anna") anna.post("/api/reisen/staedte", json=BERLIN) assert len(anna.post("/api/reisen/staedte", json=BERLIN).json()["cities"]) == 1 def test_land_markieren(login): anna = login("anna") assert anna.put("/api/reisen/laender/IS").json()["countries"] == ["IS"] assert anna.delete("/api/reisen/laender/IS").json()["countries"] == [] assert anna.put("/api/reisen/laender/xx").status_code == 400 # ---------- Wunschliste und Besuche ---------- import io # noqa: E402 from PIL import Image # noqa: E402 from app.config import DATA_DIR # noqa: E402 PRAG = {"geonameId": 3067696, "name": "Prag", "country": "CZ", "lat": 50.08, "lon": 14.42, "capital": True} def foto(client) -> str: buf = io.BytesIO() Image.new("RGB", (8, 8), "blue").save(buf, "JPEG") return client.post("/api/uploads", content=buf.getvalue()).json()["file"] def test_wunschliste(login): anna, ben = login("anna"), login("ben") data = anna.post("/api/reisen/staedte", json={**PRAG, "wish": True}).json() prag = data["cities"][0] assert prag["wish"] is True assert ben.get("/api/reisen").json()["others"] == [] # Wünsche sehen andere nicht data = anna.patch(f"/api/reisen/staedte/{prag['id']}", json={"wish": False}).json() assert data["cities"][0]["wish"] is False assert [p["name"] for p in ben.get("/api/reisen").json()["others"]] == ["Anna"] def test_besuch_mit_fotos(login): anna, ben = login("anna"), login("ben") prag = anna.post("/api/reisen/staedte", json={**PRAG, "wish": True}).json()["cities"][0] f1, f2 = foto(anna), foto(anna) data = anna.post(f"/api/reisen/staedte/{prag['id']}/besuche", json={ "dateFrom": "2024-03-01", "dateTo": "2024-03-04", "companions": "Ben", "notes": "Karlsbrücke", "photos": [f1, f2], }).json() assert data["cities"][0]["wish"] is False # Besuch macht aus dem Wunsch einen Besuch visit = data["visits"][0] assert (visit["dateFrom"], visit["dateTo"], visit["companions"], visit["photos"]) == ("2024-03-01", "2024-03-04", "Ben", [f1, f2]) assert ben.get("/api/reisen").json().get("visits") == [] # Besuche sind privat # Foto entfernt → Datei gelöscht; Besuch gelöscht → alle Fotos weg anna.put(f"/api/reisen/besuche/{visit['id']}", json={**visit, "photos": [f1]}) assert not (DATA_DIR / "uploads" / f2).exists() anna.delete(f"/api/reisen/besuche/{visit['id']}") assert not (DATA_DIR / "uploads" / f1).exists() def test_stadt_loeschen_entfernt_fotos(login): anna = login("anna") prag = anna.post("/api/reisen/staedte", json=PRAG).json()["cities"][0] f = foto(anna) anna.post(f"/api/reisen/staedte/{prag['id']}/besuche", json={"dateFrom": "2023-05-01", "photos": [f]}) anna.delete(f"/api/reisen/staedte/{prag['id']}") assert not (DATA_DIR / "uploads" / f).exists() def test_besuch_pruefungen(login): anna, ben = login("anna"), login("ben") prag = anna.post("/api/reisen/staedte", json=PRAG).json()["cities"][0] url = f"/api/reisen/staedte/{prag['id']}/besuche" assert anna.post(url, json={"dateFrom": "2024-13-01"}).status_code == 400 assert anna.post(url, json={"dateFrom": "2024-05-02", "dateTo": "2024-05-01"}).status_code == 400 assert anna.post(url, json={"dateFrom": "2024-05-02", "photos": ["../../etc/passwd"]}).status_code == 400 assert anna.post(url, json={"dateFrom": "2024-05-02", "photos": ["9e" * 12 + ".jpg"]}).status_code == 400 # gibt es nicht assert ben.post(url, json={"dateFrom": "2024-05-02"}).status_code == 404 # fremde Stadt def test_reisefotos_ueberleben_aufraeumen(login): """Das Aufräumen verwaister Bilder darf Reisefotos nicht löschen.""" from app import projects anna = login("anna") prag = anna.post("/api/reisen/staedte", json=PRAG).json()["cities"][0] f = foto(anna) anna.post(f"/api/reisen/staedte/{prag['id']}/besuche", json={"dateFrom": "2023-05-01", "photos": [f]}) import os, time old = time.time() - 3 * 24 * 3600 os.utime(DATA_DIR / "uploads" / f, (old, old)) projects._cleanup_orphans() assert (DATA_DIR / "uploads" / f).exists()