feat(booth): downloadable booths — whole-booth zip + ?dl force-download (v0.1.4)
A verbatim index.html booth (e.g. edict-design-brief: a rendered brief + its
.md) had no download affordance — the page is served raw with no gallery/per-file
chrome. Adds:
- GET /b/<name>/?download=1 -> streams the whole booth as <name>.zip (attachment)
- GET /b/<name>/<file>?dl=1 -> forces Content-Disposition: attachment (html/md/
text otherwise render inline with no easy save)
- a download link on the index card (the accessible spot for verbatim booths)
and the gallery header
Tests for both; verified live against edict-design-brief on nh3-dev :8090.
This commit is contained in:
@@ -150,6 +150,37 @@ def test_booth_serves_file(client):
|
||||
assert r.content == b"\x00\x01payload"
|
||||
|
||||
|
||||
def test_booth_zip_download(client):
|
||||
# a verbatim index.html booth (no per-file chrome) is still downloadable as a zip
|
||||
c, data = client
|
||||
d = data / "brief"
|
||||
d.mkdir()
|
||||
(d / "index.html").write_text("<h1>BRIEF</h1>")
|
||||
(d / "notes.md").write_text("# notes")
|
||||
r = c.get("/b/brief/?download=1")
|
||||
assert r.status_code == 200
|
||||
assert r.headers["content-type"] == "application/zip"
|
||||
assert "attachment" in r.headers["content-disposition"]
|
||||
assert "brief.zip" in r.headers["content-disposition"]
|
||||
import io as _io
|
||||
import zipfile as _zip
|
||||
assert set(_zip.ZipFile(_io.BytesIO(r.content)).namelist()) == {"index.html", "notes.md"}
|
||||
|
||||
|
||||
def test_booth_file_force_download(client):
|
||||
# ?dl=1 forces attachment so html/md/text saves instead of rendering inline
|
||||
c, data = client
|
||||
d = data / "brief"
|
||||
d.mkdir()
|
||||
(d / "index.html").write_text("<h1>BRIEF</h1>")
|
||||
r = c.get("/b/brief/index.html")
|
||||
assert "attachment" not in r.headers.get("content-disposition", "")
|
||||
r2 = c.get("/b/brief/index.html?dl=1")
|
||||
assert r2.status_code == 200
|
||||
assert "attachment" in r2.headers["content-disposition"]
|
||||
assert "index.html" in r2.headers["content-disposition"]
|
||||
|
||||
|
||||
def test_missing_booth_404(client):
|
||||
c, _ = client
|
||||
assert c.get("/b/nope/").status_code == 404
|
||||
|
||||
Reference in New Issue
Block a user