"""Interface : jours imposés aux traces sans heures, suggestion d'après les photos, et quelques échanges avec le serveur local.""" import os import threading import urllib.parse import urllib.request from datetime import date from http.server import ThreadingHTTPServer import pytest from rtg import config, sources from rtg.interface import serveur from test_chaine import _photo, pytestmark # noqa: F401 (mêmes prérequis) def _etape(chemin, lat0, lon0): pts = "".join(f'' for i in range(50)) with open(chemin, "w") as f: f.write(f'{pts}') @pytest.fixture def voyage_sans_heures(tmp_path): racine = tmp_path / "site" voyage = racine / "Ecosse-2027" gpx, photos = tmp_path / "gpx", tmp_path / "photos" for d in (voyage, gpx, photos): d.mkdir(parents=True) _etape(gpx / "Etape 1.gpx", 55.9, 3.2) _etape(gpx / "Etape 2.gpx", 56.7, 2.24) _photo(str(photos / "P1.jpg"), "2027:06:11 10:00:00", gps=(56.75, 2.30)) config.ecrire_toml(str(racine / "site.toml"), {"titre": "Test"}) config.ecrire_toml(str(voyage / "voyage.toml"), { "titre": "Écosse", "sources": {"traces": [str(gpx)], "videos": [], "photos": [str(photos)]}}) return racine, voyage def _cfg(racine, voyage): return config.reglages_voyage(str(voyage), config.reglages_site(str(racine))) def test_jour_impose_et_suggestion(voyage_sans_heures): racine, voyage = voyage_sans_heures a = sources.analyser(str(voyage), _cfg(racine, voyage)) assert not a.journees and len(a.non_datees) == 2 medias = sources.positions_medias(str(voyage), a) par_nom = {os.path.basename(f): p for f, p in a.non_datees.items()} assert sources.suggerer_jour(par_nom["Etape 2.gpx"], medias) == (date(2027, 6, 11), 1) assert sources.suggerer_jour(par_nom["Etape 1.gpx"], medias) == (None, 0) config.modifier_toml(str(voyage / "voyage.toml"), {"dates_traces": {"Etape 1.gpx": "2027-06-10"}}) a = sources.analyser(str(voyage), _cfg(racine, voyage)) assert sorted(a.journees) == [date(2027, 6, 10)] assert [os.path.basename(f) for f in a.non_datees] == ["Etape 2.gpx"] # Le titre et les sources ont survécu à la réécriture du fichier assert config.lire_toml(str(voyage / "voyage.toml"))["titre"] == "Écosse" @pytest.fixture def client(voyage_sans_heures): racine, voyage = voyage_sans_heures app = serveur.Application(str(racine)) srv = ThreadingHTTPServer(("127.0.0.1", 0), None) port = srv.server_address[1] srv.RequestHandlerClass = serveur.creer_gestionnaire(app, port) threading.Thread(target=srv.serve_forever, daemon=True).start() def appel(chemin, donnees=None, htmx=True): req = urllib.request.Request(f"http://127.0.0.1:{port}{chemin}", data=urllib.parse.urlencode(donnees).encode() if donnees else None) if htmx: req.add_header("HX-Request", "true") try: with urllib.request.urlopen(req) as r: return r.status, r.read().decode() except urllib.error.HTTPError as e: return e.code, e.read().decode() yield appel, racine, voyage srv.shutdown() def test_serveur(client): appel, racine, voyage = client code, html = appel("/") assert code == 200 and "Écosse" in html code, html = appel("/voyage/analyse?v=Ecosse-2027") assert "2 traces à rattacher" in html and "11 juin 2027" in html # Répartir : un jour par trace dans l'ordre des noms code, html = appel("/voyage/dates-suite", {"v": "Ecosse-2027", "debut": "2027-06-10"}) assert "2 journées" in html assert config.lire_toml(str(voyage / "voyage.toml"))["dates_traces"] == { "Etape 1.gpx": "2027-06-10", "Etape 2.gpx": "2027-06-11"} # Requête de modification sans l'en-tête htmx : refusée code, _ = appel("/voyage/date", {"v": "Ecosse-2027", "fichier": "Etape 1.gpx", "jour": ""}, htmx=False) assert code == 403 # Voyage hors du site : refusé code, html = appel("/voyage/analyse?v=../../etc") assert "introuvable" in html.lower()