mirror of
https://github.com/zvx-echo6/recon.git
synced 2026-06-10 00:44:37 +02:00
Per-tag HTTP wrapper over wiki_rewrite.rewrite_wiki_link so the (future) navi-places service can rewrite OSM wiki tags to local Kiwix URLs over HTTP instead of importing recon's wiki_rewrite module (which talks to Kiwix on localhost:8430 and the wiki_cache table in /opt/recon/data/place_cache.db). Companion to PR #8 (/api/wiki-enrich) — Matt picked option B (HTTP-couple the Kiwix offline-wiki rewriting too, since it matters in prod). GET /api/wiki-rewrite?tag=<wikipedia|wikidata|wikivoyage|appropedia>&value=<raw> -> 200 {url, status} where status is "local" | "public" | "original" -> 400 on missing value or unknown tag -> no 404 (unclassifiable value echoes back with status "original", mirroring rewrite_wiki_link) Public (no auth), like /api/place/* and /api/wiki-enrich. Changes (additive only): - lib/wiki_rewrite_api.py: new wiki_rewrite_bp blueprint. Thin route directly over the existing rewrite_wiki_link(tag, value) — no extraction needed (it's already a clean standalone function, unlike wiki-enrich's lookup). - lib/api.py: register the blueprint (one block). - lib/wiki_rewrite_api_test.py: 5 tests (local Kiwix hit, public fallback, unclassifiable -> original, missing value -> 400, unknown tag -> 400), stubbing check_kiwix_has_article (no Kiwix/DB), plain-assert + __main__ runner. Verified green against recon's venv (flask 3.1.2). Does NOT touch place_detail's in-process _enrich_wiki_links — that gets removed in a later PR once navi-places is live (same as PR #8). wiki_cache stays in recon's own place_cache.db post-cutover (harmless positive-cache duplication). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f42b1fef3b
commit
14ad2cd34a
3 changed files with 111 additions and 0 deletions
|
|
@ -77,6 +77,10 @@ app.register_blueprint(geocode_bp)
|
|||
from .wiki_enrich_api import wiki_enrich_bp
|
||||
app.register_blueprint(wiki_enrich_bp)
|
||||
|
||||
# ── Wiki-rewrite Blueprint (extraction #5 prep — HTTP wrapper over rewrite_wiki_link) ──
|
||||
from .wiki_rewrite_api import wiki_rewrite_bp
|
||||
app.register_blueprint(wiki_rewrite_bp)
|
||||
|
||||
|
||||
|
||||
# ── Navigation Constants ──
|
||||
|
|
|
|||
34
lib/wiki_rewrite_api.py
Normal file
34
lib/wiki_rewrite_api.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"""Wiki-rewrite API — read-only HTTP wrapper over wiki_rewrite.rewrite_wiki_link.
|
||||
|
||||
Extraction #5 prep: lets the (future) navi-places service rewrite OSM wiki tags
|
||||
to local Kiwix URLs over HTTP instead of importing recon's wiki_rewrite module
|
||||
(which talks to Kiwix and the wiki_cache table in /opt/recon/data/place_cache.db).
|
||||
Additive only — does not change place_detail's in-process `_enrich_wiki_links`.
|
||||
|
||||
GET /api/wiki-rewrite?tag=<wikipedia|wikidata|wikivoyage|appropedia>&value=<raw>
|
||||
|
||||
Public (no auth), matching /api/place/* and /api/wiki-enrich. 400 on missing
|
||||
value or unknown tag. No 404 — an unclassifiable value returns the original
|
||||
value with status "original" (mirrors rewrite_wiki_link).
|
||||
"""
|
||||
from flask import Blueprint, request, jsonify
|
||||
|
||||
from .wiki_rewrite import rewrite_wiki_link
|
||||
|
||||
wiki_rewrite_bp = Blueprint('wiki_rewrite', __name__)
|
||||
|
||||
_KNOWN_TAGS = {'wikipedia', 'wikidata', 'wikivoyage', 'appropedia'}
|
||||
|
||||
|
||||
@wiki_rewrite_bp.route('/api/wiki-rewrite')
|
||||
def api_wiki_rewrite():
|
||||
tag = (request.args.get('tag') or '').strip().lower()
|
||||
value = (request.args.get('value') or '').strip()
|
||||
|
||||
if not value:
|
||||
return jsonify({'error': 'value is required'}), 400
|
||||
if tag not in _KNOWN_TAGS:
|
||||
return jsonify({'error': f"tag must be one of {sorted(_KNOWN_TAGS)}"}), 400
|
||||
|
||||
url, status = rewrite_wiki_link(tag, value)
|
||||
return jsonify({'url': url, 'status': status})
|
||||
73
lib/wiki_rewrite_api_test.py
Normal file
73
lib/wiki_rewrite_api_test.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
"""Tests for the /api/wiki-rewrite endpoint (extraction #5 prep).
|
||||
|
||||
Plain-assert style (recon's venv has no pytest). Builds a minimal Flask app
|
||||
with only wiki_rewrite_bp registered. Mocks `wiki_rewrite.check_kiwix_has_article`
|
||||
to control the local-Kiwix-hit vs. fallback paths without touching Kiwix or the
|
||||
wiki_cache DB. classify_wiki_link (pure regex) runs for real. Run with pytest,
|
||||
or directly: python -m lib.wiki_rewrite_api_test
|
||||
"""
|
||||
from flask import Flask
|
||||
|
||||
from lib import wiki_rewrite
|
||||
from lib.wiki_rewrite_api import wiki_rewrite_bp
|
||||
|
||||
|
||||
def _client(kiwix_hit):
|
||||
"""kiwix_hit: (found_bool, url) returned by a stubbed check_kiwix_has_article."""
|
||||
wiki_rewrite.check_kiwix_has_article = lambda source_type, article_id: kiwix_hit
|
||||
app = Flask(__name__)
|
||||
app.register_blueprint(wiki_rewrite_bp)
|
||||
return app.test_client()
|
||||
|
||||
|
||||
def test_local_kiwix_hit():
|
||||
url = "https://wiki.echo6.co/content/wikipedia/Filer,_Idaho"
|
||||
c = _client((True, url))
|
||||
resp = c.get("/api/wiki-rewrite?tag=wikipedia&value=Filer, Idaho")
|
||||
assert resp.status_code == 200, resp.status_code
|
||||
d = resp.get_json()
|
||||
assert d["status"] == "local"
|
||||
assert d["url"] == url
|
||||
|
||||
|
||||
def test_public_fallback_when_not_in_kiwix():
|
||||
c = _client((False, None)) # not in Kiwix -> canonical public URL
|
||||
resp = c.get("/api/wiki-rewrite?tag=wikipedia&value=Filer")
|
||||
assert resp.status_code == 200, resp.status_code
|
||||
d = resp.get_json()
|
||||
assert d["status"] == "public"
|
||||
assert d["url"] == "https://en.wikipedia.org/wiki/Filer"
|
||||
|
||||
|
||||
def test_unclassifiable_returns_original():
|
||||
# 'wikidata' requires a Q-id; a non-matching value -> classify None -> original.
|
||||
c = _client((False, None))
|
||||
resp = c.get("/api/wiki-rewrite?tag=wikidata&value=not-a-qid")
|
||||
assert resp.status_code == 200, resp.status_code
|
||||
d = resp.get_json()
|
||||
assert d["status"] == "original"
|
||||
assert d["url"] == "not-a-qid"
|
||||
|
||||
|
||||
def test_missing_value_400():
|
||||
c = _client((False, None))
|
||||
assert c.get("/api/wiki-rewrite?tag=wikipedia").status_code == 400
|
||||
|
||||
|
||||
def test_unknown_tag_400():
|
||||
c = _client((False, None))
|
||||
assert c.get("/api/wiki-rewrite?tag=facebook&value=x").status_code == 400
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
failures = 0
|
||||
for _name, _fn in sorted(globals().items()):
|
||||
if _name.startswith("test_") and callable(_fn):
|
||||
try:
|
||||
_fn()
|
||||
print(f"PASS {_name}")
|
||||
except Exception as exc: # noqa: BLE001
|
||||
failures += 1
|
||||
print(f"FAIL {_name}: {exc!r}")
|
||||
print("OK" if failures == 0 else f"{failures} FAILED")
|
||||
raise SystemExit(1 if failures else 0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue