Publish snippets and Markdown posts through authenticated uploads

This commit is contained in:
2026-09-19 15:34:17 +03:30
parent 17f1a8ef39
commit e42646e09e
14 changed files with 553 additions and 15 deletions
+56
View File
@@ -5,6 +5,7 @@ from pathlib import Path
import subprocess
import sys
import os
import random
import pytest
from PIL import Image
@@ -59,6 +60,16 @@ def test_validation_is_all_or_nothing(service):
assert not list((data / "temporary").iterdir())
def test_multi_megabyte_multipart_file(service):
_, client, _ = service
output = io.BytesIO()
Image.frombytes("RGB", (1800, 1800), random.Random(2).randbytes(1800 * 1800 * 3)).save(
output, "JPEG", quality=95)
assert len(output.getvalue()) > 3 * 1024 * 1024
response = upload(client, [output.getvalue()])
assert response.status_code == 202, response.json
def test_album_caption_order_and_retry_deduplication(service):
_, client, data = service
caption = '<script>alert(1)</script> {% include secret %} {{ site.email }}\nsecond line'
@@ -149,6 +160,7 @@ def publisher(tmp_path, service):
git(source, "config", "user.name", "Test")
git(source, "config", "user.email", "test@example.com")
(source / "art.html").write_text("Initial site")
(source / "snippets.md").write_text("---\nlayout: post\n---\nIntroduction\n\n<!-- uploaded-snippets -->\n\nOld snippet\n")
git(source, "add", ".")
git(source, "commit", "-m", "Initial")
git(source, "remote", "add", "origin", str(remote))
@@ -200,3 +212,47 @@ def test_rejected_push_can_retry(publisher):
result = run()
assert result.returncode == 0, result.stderr
assert client.get(response.json["status_url"], headers=AUTH).json["status"] == "pushed"
def test_snippet_intake_validation_and_literal_text(service):
_, client, data = service
assert client.post("/api/snippets", data={"text": "hello"}).status_code == 401
assert client.post("/api/snippets", headers=AUTH).status_code == 400
assert client.post("/api/snippets", headers=AUTH, data={"text": "x" * 20001}).status_code == 400
text = 'Book quote\nفارسی <script>bad</script> {% include secret %}\nhttps://example.com/?a=1&b=2'
response = client.post("/api/snippets", headers=AUTH, data={"text": text})
assert response.status_code == 202
job = response.json["id"]
assert response.json["url"] == f"/snippets/#snippet-{job}"
assert client.get(f"/api/photos/{job}", headers=AUTH).status_code == 404
entry = (data / "submissions" / job / "entry.md").read_text()
assert '<script>' not in entry and '{%' not in entry
assert '<p dir="auto">Book quote<br>\nفارسی' in entry
assert '<a href="https://example.com/?a=1&amp;b=2">' in entry
assert client.post("/api/snippets", headers=AUTH, data={"text": text}).status_code == 200
assert client.post("/api/snippets", headers=AUTH, data={"photos": (io.BytesIO(b"bad"), "bad.jpg")}).status_code == 400
def test_snippet_prepend_images_recovery_and_receipt(publisher, service, monkeypatch, tmp_path):
run, remote, client = publisher
_, _, data = service
first = client.post("/api/snippets", headers=AUTH, data={"text": "First snippet"}).json
second = client.post("/api/snippets", headers=AUTH, data={
"caption": "Image note", "photos": (io.BytesIO(photo()), "photo.jpg"),
}).json
result = run()
assert result.returncode == 0, result.stderr
content = git(remote, "show", "master:snippets.md")
assert content.startswith("---\nlayout: post\n---\nIntroduction")
assert content.index(second["id"]) < content.index(first["id"]) < content.index("Old snippet")
assert f'img/snippets/uploads/{second["id"]}/00.jpg' in git(remote, "ls-tree", "-r", "--name-only", "master")
head = git(remote, "rev-parse", "master")
for job in (first["id"], second["id"]):
(data / "status" / f"{job}.json").write_text('{"status":"failed"}')
assert client.post(f"/api/snippets/{job}/retry", headers=AUTH).json["status"] == "queued"
assert run().returncode == 0
assert git(remote, "rev-parse", "master") == head
receipt = tmp_path / "deployed.json"
monkeypatch.setenv("PHOTO_DEPLOYMENT_FILE", str(receipt))
receipt.write_text(json.dumps({"snippets": [first["id"], second["id"]]}))
assert client.get(first["status_url"], headers=AUTH).json["status"] == "published"