Files
thejayman77 2cfffdfd6a NEWS RELAUNCH CUTOVER: promote the hub to /, feed to /news, go public
The big flip. /home3 (hub) becomes /; the feed lives at /news; both indexable.
- PROMOTE: routes/+page.svelte is now the hub (was the interim NewsFeed wrapper);
  noindex removed; "Read more good news" → /news. routes/home3 + home2 deleted.
- routes/+page.js: redirects legacy root-query links (/?view=latest, /?tag, /?source,
  /?q, /?view=today→highlights) to /news before the hub renders (no flash).
- /news: noindex dropped (route meta + Caddy @newsHidden removed); now public.
- LINKS: HubBar brand/Home → /, News default → /news; HubShell/art/play back → /;
  account Following + share.py Explore/Browse/source → /news.
- FOOTER: one shared Footer.svelte (motto + Send feedback + slot) across Hub/News/
  Play/Art/HubShell/Account/Zen; global layout footer removed (FeedbackModal stays).
- SITEMAP: + /news /art /play /word /quote /onthisday; cap 5k→50k; gated on
  has-summary; paywalled excluded; HEAD now 200 (api_route GET+HEAD).
- Head-patcher: /news entry. PWA + shell description broadened to the hub.
- Caddy: @newsHidden dropped; @hidden now admin-only (word/quote/onthisday public);
  /home2,/home3 → / 301. Mirrored to deploy/caddy snapshot.

425 backend + 36 frontend tests green; build clean; Caddy valid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:16:43 -04:00

72 lines
3.4 KiB
Python

import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def client(tmp_path, monkeypatch):
db = tmp_path / "t.sqlite3"
monkeypatch.setenv("GOODNEWS_DB", str(db))
monkeypatch.setenv("GOODNEWS_PUBLIC_BASE_URL", "https://upbeatbytes.com")
import importlib
import goodnews.api as api
importlib.reload(api)
from goodnews.db import connect, init_db
c = connect(str(db)); init_db(c)
c.execute("INSERT INTO sources (id,name,feed_url,trust_score) VALUES (1,'BBC','http://s/f',5)")
c.execute("INSERT INTO articles (id,source_id,canonical_url,title,url_hash,published_at) "
"VALUES (1,1,'https://bbc.com/x','Bees are back','h1','2026-06-05T08:00:00')")
c.execute("INSERT INTO article_scores (article_id,accepted,reason_text) VALUES (1,1,'Hopeful.')")
c.execute("INSERT INTO article_summaries (article_id,summary) VALUES (1,'Bee numbers recovered after a restoration effort.')")
c.execute("INSERT INTO daily_briefs (id,brief_date,title) VALUES (1,'2026-06-05','B')")
c.execute("INSERT INTO daily_brief_items (brief_id,article_id,rank) VALUES (1,1,1)")
c.commit(); c.close()
return api.create_app()
def test_today_digest(client):
r = TestClient(client).get("/today")
assert r.status_code == 200
html = r.text
assert "Bees are back" in html
assert "Bee numbers recovered" in html # our summary
assert 'href="/a/1"' in html and "bbc.com/x" in html # summary + source links
assert 'rel="canonical" href="https://upbeatbytes.com/today"' in html
assert 'property="og:title"' in html
def test_sitemap(client):
r = TestClient(client).get("/sitemap.xml")
assert r.status_code == 200
assert "application/xml" in r.headers["content-type"]
xml = r.text
assert "<urlset" in xml
assert "https://upbeatbytes.com/a/1" in xml
assert "https://upbeatbytes.com/today" in xml
assert "<lastmod>2026-06-05</lastmod>" in xml
def test_sitemap_excludes_paywalled_and_restores_on_free(tmp_path, monkeypatch):
db = tmp_path / "sm.sqlite3"
monkeypatch.setenv("GOODNEWS_DB", str(db))
monkeypatch.setenv("GOODNEWS_PUBLIC_BASE_URL", "https://upbeatbytes.com")
import importlib
import goodnews.api as api
importlib.reload(api)
from goodnews.db import connect, init_db
c = connect(str(db)); init_db(c)
c.execute("INSERT INTO sources (id,name,feed_url,trust_score,content_visible) VALUES (1,'Free','http://f',5,1)")
c.execute("INSERT INTO sources (id,name,feed_url,trust_score,content_visible,paywall_override) "
"VALUES (2,'Pay','http://p',5,1,'paywalled')")
for aid, sid in [(1, 1), (2, 2)]:
c.execute("INSERT INTO articles (id,source_id,canonical_url,title,url_hash,published_at) VALUES (?,?,?,?,?,?)",
(aid, sid, f"http://x/{aid}", f"t{aid}", f"h{aid}", "2026-06-05T08:00:00"))
c.execute("INSERT INTO article_scores (article_id,accepted) VALUES (?,1)", (aid,))
c.execute("INSERT INTO article_summaries (article_id,summary) VALUES (?,?)", (aid, f"s{aid}")) # sitemap requires a summary
c.commit()
tc = TestClient(api.create_app())
xml = tc.get("/sitemap.xml").text
assert "/a/1</loc>" in xml and "/a/2</loc>" not in xml # paywalled source omitted
c.execute("UPDATE sources SET paywall_override='free' WHERE id=2"); c.commit()
assert "/a/2</loc>" in tc.get("/sitemap.xml").text # restored under 'free'
c.close()