diff --git a/soapbox/admin.py b/soapbox/admin.py
index 10efd7c..5fa156e 100644
--- a/soapbox/admin.py
+++ b/soapbox/admin.py
@@ -339,7 +339,7 @@ def history(post_id: str):
sha = request.args.get("sha")
diff = None
if sha:
- diff = gitstore.path_diff(cfg.content_dir, sha, rel)
+ diff = gitstore.path_diff(cfg.content_dir, sha)
if diff is None:
abort(404)
return render_template("admin/history.html", post=post, entries=entries, sha=sha, diff=diff)
diff --git a/soapbox/build.py b/soapbox/build.py
index d210388..36b833c 100644
--- a/soapbox/build.py
+++ b/soapbox/build.py
@@ -63,6 +63,7 @@ def build_site(cfg: Config) -> int:
return env.get_template(template).render(
site=site,
source_url=SOURCE_URL,
+ site_url=cfg.site_url, # absolutt; kun for Open Graph/canonical
page_path=page_path,
rel=lambda target: relative_to(page_path, target),
now=datetime.now(UTC),
@@ -93,6 +94,7 @@ def build_site(cfg: Config) -> int:
)
_write(tmp / "feed.xml", _feed(cfg, site, posts[:20]))
+ _write(tmp / "sitemap.xml", _sitemap(cfg, posts, sorted(guests)))
# Statiske filer lagvis: innebygd først, eget tema oppå (overskriver).
for d in reversed(cfg.theme_dirs):
@@ -111,6 +113,27 @@ def build_site(cfg: Config) -> int:
return len(posts)
+def _sitemap(cfg: Config, posts: list[Post], guests: list[str]) -> str:
+ """sitemap.xml med forsiden, alle innlegg og gjesteoversiktene."""
+ base = cfg.site_url + "/"
+
+ def url(path: str, lastmod: datetime | None = None) -> str:
+ loc = f"{escape(base + quote(path))}"
+ mod = f"{lastmod.date().isoformat()}" if lastmod else ""
+ return f"{loc}{mod}"
+
+ newest = posts[0].updated or posts[0].date if posts else None
+ entries = [url("", newest)]
+ entries += [url(p.url_path, p.updated or p.date) for p in posts]
+ entries += [url(f"{g}/") for g in guests]
+ return (
+ '\n'
+ ''
+ + "".join(entries)
+ + "\n"
+ )
+
+
def _feed(cfg: Config, site: dict, posts: list[Post]) -> str:
base = cfg.site_url + "/"
items = []
diff --git a/soapbox/gitstore.py b/soapbox/gitstore.py
index 0c3d2bb..3ab64b1 100644
--- a/soapbox/gitstore.py
+++ b/soapbox/gitstore.py
@@ -45,21 +45,11 @@ def log(repo: Path, limit: int = 20) -> list[str]:
return out.stdout.splitlines() if out.returncode == 0 else []
-def path_log(repo: Path, path: str, limit: int = 50) -> list[dict]:
- """Commits som har rørt ``path`` (relativ til repo), nyeste først.
+_LOG_FORMAT = "--format=%H%x1f%aI%x1f%an%x1f%s"
- Merk: en katalog som ble omdøpt (slug endret mens innlegget var utkast)
- mister historikken fra før omdøpingen – git følger bare filer, ikke mapper.
- """
- out = _git(
- repo,
- "log",
- f"-{limit}",
- "--format=%H%x1f%aI%x1f%an%x1f%s",
- "--",
- path,
- check=False,
- )
+
+def _log(repo: Path, *args: str) -> list[dict]:
+ out = _git(repo, "log", _LOG_FORMAT, *args, check=False)
entries = []
for line in out.stdout.splitlines():
sha, date, author, subject = line.split("\x1f", 3)
@@ -67,9 +57,29 @@ def path_log(repo: Path, path: str, limit: int = 50) -> list[dict]:
return entries
-def path_diff(repo: Path, sha: str, path: str) -> str | None:
- """Diff for ``path`` i én commit, eller None hvis commit-en ikke finnes."""
+def path_log(repo: Path, path: str, limit: int = 50) -> list[dict]:
+ """Commits som har rørt innleggsmappen ``path`` (relativ til repo), nyeste først.
+
+ git følger filer, ikke mapper, så en katalog som ble omdøpt (slug endret
+ mens innlegget var utkast) ville mistet historikken fra før omdøpingen.
+ Derfor kombineres to logger: ``--follow`` på ``index.md`` (tar med tiden
+ før omdøpingen) og en vanlig logg på mappen (tar med bildeopplastinger).
+ """
+ seen: dict[str, dict] = {}
+ for e in _log(repo, f"-{limit}", "--follow", "--", f"{path}/index.md") + _log(
+ repo, f"-{limit}", "--", path
+ ):
+ seen.setdefault(e["sha"], e)
+ return sorted(seen.values(), key=lambda e: e["date"], reverse=True)[:limit]
+
+
+def path_diff(repo: Path, sha: str) -> str | None:
+ """Diff for én commit, eller None hvis commit-en ikke finnes.
+
+ Diffen begrenses ikke til innleggets nåværende sti: før en omdøping lå
+ filene et annet sted, og hver commit er uansett én handling på ett innlegg.
+ """
if not all(c in "0123456789abcdef" for c in sha) or len(sha) < 7:
return None
- out = _git(repo, "show", "--format=", "--stat", "--patch", sha, "--", path, check=False)
+ out = _git(repo, "show", "--format=", "--stat", "--patch", sha, check=False)
return out.stdout if out.returncode == 0 else None
diff --git a/soapbox/themes/green/templates/base.html b/soapbox/themes/green/templates/base.html
index 3393fe8..1b4c25a 100644
--- a/soapbox/themes/green/templates/base.html
+++ b/soapbox/themes/green/templates/base.html
@@ -8,6 +8,14 @@
+{# Open Graph krever absolutte URL-er; site_url er det eneste stedet det brukes utenom feed/sitemap. #}
+{% block og %}
+
+
+
+
+{% if site.description %}{% endif %}
+{% endblock %}
Hopp til innhold
diff --git a/soapbox/themes/green/templates/post.html b/soapbox/themes/green/templates/post.html
index e622ddf..443cff5 100644
--- a/soapbox/themes/green/templates/post.html
+++ b/soapbox/themes/green/templates/post.html
@@ -1,5 +1,20 @@
{% extends "base.html" %}
{% block title %}{{ post.title }} – {{ site.title }}{% endblock %}
+{% block og %}
+{% set summary = post.body|excerpt(200) %}
+
+
+
+
+
+{% if summary %}
+{% endif %}
+{% if post.images %}{% endif %}
+
+{% if post.updated %}{% endif %}
+{% if post.author %}{% endif %}
+
+{% endblock %}
{% block content %}
{{ post.title }}
diff --git a/tests/test_app.py b/tests/test_app.py
index d25b8b2..d13f5e9 100644
--- a/tests/test_app.py
+++ b/tests/test_app.py
@@ -180,6 +180,7 @@ def test_post_history(client, cfg):
html = client.get(f"/admin/history/{pid}").text
assert "Publiserte: Hist" in html and "Lagret: Hist" in html
+ assert "Opprettet utkast" in html # fra før slug-omdøpingen (--follow)
sha = re.search(r"sha=([0-9a-f]{40})", html).group(1)
diff = client.get(f"/admin/history/{pid}?sha={sha}").text
assert '+andre' in diff and '-første' in diff
@@ -264,3 +265,34 @@ def test_logo_links_to_blog_root(client):
assert '' in html
+ assert '' in html
+ assert '' in html
+ assert '' in html
+ assert '' in html
+ assert '' in client.get("/").text
+ sm = client.get("/sitemap.xml")
+ assert sm.status_code == 200
+ assert "https://blog.example.no/" in sm.text
+ assert "https://blog.example.no/og-test/" in sm.text