Reisen: Wunschliste, Besuche mit Fotos, Zeitleiste und Statistik
- Wunschliste (Spalte travel_cities.wish): eigene Punktform auf der Karte, zählt nicht als besucht, für andere Konten unsichtbar; "War ich da ✓" - Besuche je Stadt (Tabellen travel_visits, travel_visit_photos): Zeitraum, Begleitung, Notizen, Fotos (Upload ohne Metadaten); nur für das eigene Konto; ein Besuch macht aus einem Wunsch einen Besuch - Fotos von Besuchen zählen beim Aufräumen verwaister Bilder als benutzt; beim Entfernen eines Fotos, Besuchs oder einer Stadt werden die Dateien gelöscht - Zeitleiste "Wann war ich wo?" nach Jahren, Fotos mit Lightbox - Statistik: Länder (Welt, je Kontinent), Landfläche, äußerste Orte, Kilometer entlang der Besuche - Ansichten unter der Karte als Tabs: Besuchte Orte, Zeitleiste, Statistik, Wunschliste - Migration Schritt 4, Tests für Wunschliste, Besuche, Fotos und Aufräumen Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9835f5e69e
commit
bbf740603e
16 files changed
+695
-32
No files matched your search
@@ -32,3 +32,83 @@ def test_land_markieren(login):
|
||||
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()
|
||||
Reference in new issue
Block a user