Files
felhom.eu/documentation/audits/website-refresh-2026-10-08/tools/common.py
T
admin 67b3fd23d1
gates / gates (push) Failing after 13m1s
website refresh: true numbers (56 apps), claims checked against the capability map, ten missing apps, an English twin of every public page (public, choice B), 404 page; site gates 13-18 + 11 decoys; R-902 opened
Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected
from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed
mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube,
radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins,
nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py
twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11,
§10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 08:29:17 +02:00

121 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
"""Shared pieces of the website refresh 2026-10-08: the page map, the two navs, hreflang, file IO."""
import io, os, re, subprocess
REPO = "/mnt/5_hdd/felhom.eu/git/felhom.eu"
W = os.path.join(REPO, "website")
SITE = "https://felhom.eu"
# hu file, hu url, en file, en url, hu nav href that is "active", en nav href that is "active"
PAIRS = [
("index.html", "/", "en/index.html", "/en/", None, None),
("alkalmazasok.html", "/alkalmazasok", "en/apps.html", "/en/apps", "/alkalmazasok", "/en/apps"),
("technologiak.html", "/technologiak", "en/technology.html", "/en/technology", "/technologiak", "/en/technology"),
("biztonsagimentes.html", "/biztonsagimentes", "en/backups.html", "/en/backups", "/biztonsagimentes", "/en/backups"),
("gyik.html", "/gyik", "en/faq.html", "/en/faq", "/gyik", "/en/faq"),
("kapcsolat.html", "/kapcsolat", "en/contact.html", "/en/contact", "/kapcsolat", "/en/contact"),
("letoltes.html", "/letoltes", "en/download.html", "/en/download", None, None),
]
HU_ITEMS = [("/#szolgaltatasok", "Szolgáltatások"), ("/alkalmazasok", "Alkalmazások"), ("/technologiak", "Technológiák"),
("/biztonsagimentes", "Mentések"), ("/gyik", "GYIK"), ("/kapcsolat", "Kapcsolat")]
EN_ITEMS = [("/en/#services", "Services"), ("/en/apps", "Apps"), ("/en/technology", "Technology"),
("/en/backups", "Backups"), ("/en/faq", "FAQ"), ("/en/contact", "Contact")]
def nav(lang, active, twin_url):
items = HU_ITEMS if lang == "hu" else EN_ITEMS
lis = []
for href, label in items:
act = ' class="active"' if href == active else ""
lis.append(' <li><a href="%s"%s>%s</a></li>' % (href, act, label))
if lang == "hu":
lis.append(' <li><a href="%s" lang="en" hreflang="en" class="lang-switch">English</a></li>' % twin_url)
else:
lis.append(' <li><a href="%s" lang="hu" hreflang="hu" class="lang-switch">Magyar</a></li>' % twin_url)
home = "/" if lang == "hu" else "/en/"
open_l = "Menü megnyitása" if lang == "hu" else "Open menu"
return (""" <nav>
<div class="container">
<a href="%s" class="logo">
<img src="/assets/logo.png" alt="Felhom.eu logo">
<span class="logo-text">felhom.eu</span>
</a>
<ul class="nav-links">
%s
</ul>
<button class="hamburger" id="hamburger" aria-label="%s" aria-expanded="false">
<span class="hamburger-box">
<span class="hamburger-line"></span>
<span class="hamburger-line"></span>
<span class="hamburger-line"></span>
</span>
</button>
</div>
</nav>""" % (home, "\n".join(lis), open_l))
FOOTER_HU = """ <footer>
<div class="container">
<p>© 2026 felhom.eu — Saját felhőd, saját szabályaid</p>
</div>
</footer>"""
FOOTER_EN = """ <footer>
<div class="container">
<p>© 2026 felhom.eu — Your own cloud, your own rules. Felhom serves households in Hungary.</p>
</div>
</footer>"""
def alternates(hu_url, en_url):
return (' <link rel="alternate" hreflang="hu" href="%s%s">\n'
' <link rel="alternate" hreflang="en" href="%s%s">\n'
' <link rel="alternate" hreflang="x-default" href="%s%s">') % (SITE, hu_url, SITE, en_url, SITE, hu_url)
def head_text(path):
"""The file as it is at HEAD (the source every build starts from, so a re-run is idempotent)."""
rel = os.path.relpath(os.path.join(W, path), REPO)
out = subprocess.run(["git", "-C", REPO, "show", "HEAD:" + rel], capture_output=True)
if out.returncode != 0:
return None
return out.stdout.decode("utf-8-sig")
def read(path):
return io.open(os.path.join(W, path), encoding="utf-8-sig").read()
def write(path, text):
full = os.path.join(W, path)
os.makedirs(os.path.dirname(full), exist_ok=True)
with io.open(full, "w", encoding="utf-8-sig", newline="\n") as f:
f.write(text)
def sub1(s, old, new, count=1):
n = s.count(old)
if n != count:
raise SystemExit("expected %d x %r, found %d" % (count, old[:90], n))
return s.replace(old, new)
def set_nav(s, lang, active, twin_url):
s2, n = re.subn(r" <nav>.*?</nav>", lambda m: nav(lang, active, twin_url), s, count=1, flags=re.S)
assert n == 1
return s2
def set_footer(s, lang):
s2, n = re.subn(r" <footer>.*?</footer>", lambda m: FOOTER_HU if lang == "hu" else FOOTER_EN, s, count=1, flags=re.S)
assert n == 1
return s2
def set_alternates(s, hu_url, en_url):
"""Insert (or replace) the three hreflang links right after the canonical link."""
s = re.sub(r' <link rel="alternate" hreflang="[^"]+" href="[^"]+">\n', "", s)
m = re.search(r' <link rel="canonical" href="[^"]+">\n', s)
assert m, "no canonical"
return s[:m.end()] + alternates(hu_url, en_url) + "\n" + s[m.end():]