"""NewsTemplateRepository — repository-level tests for the v29 news entity. Covers the draft singleton invariant, monotonic versioning, publish / unpublish flow, sanitization on save, and the prune rule (drop >30d EXCEPT the currently-displayed published version). """ from __future__ import annotations import tempfile import pytest @pytest.fixture def fresh_db(monkeypatch): with tempfile.TemporaryDirectory() as tmp: monkeypatch.setenv("DATA_DIR", tmp) monkeypatch.setenv("TESTING", "1") monkeypatch.setenv("JWT_SECRET_KEY", "test-jwt-secret-key-minimum-32-chars!!") yield tmp def _conn(): from src.db import get_system_db return get_system_db() def test_initial_state_no_published_no_draft(fresh_db): from src.repositories.news_template import NewsTemplateRepository conn = _conn() try: repo = NewsTemplateRepository(conn) assert repo.get_current_published() is None assert repo.get_active_draft() is None assert repo.list_versions() == [] finally: conn.close() def test_save_draft_creates_row_then_updates_in_place(fresh_db): from src.repositories.news_template import NewsTemplateRepository conn = _conn() try: repo = NewsTemplateRepository(conn) a = repo.save_draft(intro="

a

", content="

A

", by="alice@x") assert a["version"] == 1 assert a["published"] is False assert a["created_by"] == "alice@x" # Second save while draft active must update the same row. b = repo.save_draft(intro="

b

", content="

B

", by="alice@x") assert b["version"] == 1, "draft should update in place, not bump version" assert b["intro"] == "

b

" rows = repo.list_versions() assert len(rows) == 1 assert rows[0]["status"] == "draft" finally: conn.close() def test_publish_then_new_draft_increments_version(fresh_db): from src.repositories.news_template import NewsTemplateRepository conn = _conn() try: repo = NewsTemplateRepository(conn) repo.save_draft(intro="

v1

", content="

V1

", by="alice@x") p1 = repo.publish_draft(by="alice@x") assert p1["version"] == 1 assert p1["published"] is True assert repo.get_active_draft() is None d2 = repo.save_draft(intro="

v2

", content="

V2

", by="alice@x") assert d2["version"] == 2 assert d2["published"] is False # Web sees only the published v1 until v2 is published. cp = repo.get_current_published() assert cp is not None and cp["version"] == 1 finally: conn.close() def test_publish_with_no_draft_raises(fresh_db): from src.repositories.news_template import NewsTemplateRepository, NoDraftError conn = _conn() try: repo = NewsTemplateRepository(conn) with pytest.raises(NoDraftError): repo.publish_draft(by="alice@x") finally: conn.close() def test_unpublish_falls_back_to_prior_published(fresh_db): from src.repositories.news_template import NewsTemplateRepository conn = _conn() try: repo = NewsTemplateRepository(conn) repo.save_draft(intro="

v1

", content="V1", by="alice@x") repo.publish_draft(by="alice@x") repo.save_draft(intro="

v2

", content="V2", by="alice@x") repo.publish_draft(by="alice@x") cp = repo.get_current_published() assert cp["version"] == 2 # Unpublish v2 — web should fall back to v1. repo.unpublish(version=2, by="alice@x") cp2 = repo.get_current_published() assert cp2 is not None and cp2["version"] == 1 finally: conn.close() def test_unpublish_blocked_when_draft_active(fresh_db): from src.repositories.news_template import ( AlreadyDraftError, NewsTemplateRepository, ) conn = _conn() try: repo = NewsTemplateRepository(conn) repo.save_draft(intro="

v1

", content="V1", by="alice@x") repo.publish_draft(by="alice@x") repo.save_draft(intro="

v2 draft

", content="V2", by="alice@x") with pytest.raises(AlreadyDraftError): repo.unpublish(version=1, by="alice@x") finally: conn.close() def test_unpublish_unknown_version_raises_not_found(fresh_db): from src.repositories.news_template import NewsTemplateRepository, NotFoundError conn = _conn() try: repo = NewsTemplateRepository(conn) with pytest.raises(NotFoundError): repo.unpublish(version=99, by="alice@x") finally: conn.close() def test_unpublish_already_draft_raises(fresh_db): from src.repositories.news_template import ( AlreadyDraftError, NewsTemplateRepository, ) conn = _conn() try: repo = NewsTemplateRepository(conn) repo.save_draft(intro="

v1

", content="V1", by="alice@x") # version 1 is a draft, not published — unpublish should refuse with pytest.raises(AlreadyDraftError): repo.unpublish(version=1, by="alice@x") finally: conn.close() def test_save_draft_sanitizes_input(fresh_db): from src.repositories.news_template import NewsTemplateRepository conn = _conn() try: repo = NewsTemplateRepository(conn) repo.save_draft( intro="

hi

", content='

ok

', by="alice@x", ) d = repo.get_active_draft() assert "