Remove contributing and component docs from the public docs site
Drop the Contributing and internals section, Architecture, Frontend, and dp-* component pages from the docs registry, prose files, nav, and legacy redirect target. Guard with tests that fail if they return.
This commit is contained in:
+1
-13
@@ -10,9 +10,7 @@ from molodetz.rendering import normalize_dashes
|
|||||||
|
|
||||||
PROSE_DIR = config.TEMPLATES_DIR / "docs" / "prose"
|
PROSE_DIR = config.TEMPLATES_DIR / "docs" / "prose"
|
||||||
|
|
||||||
SECTIONS = ("Start here", "Building with the API", "Contributing and internals", "Admin")
|
SECTIONS = ("Start here", "Building with the API", "Admin")
|
||||||
|
|
||||||
COMPONENTS = ("avatar", "code", "content", "title", "toast", "dialog", "context-menu", "upload", "lightbox", "chat")
|
|
||||||
|
|
||||||
DOCS_PAGES = [
|
DOCS_PAGES = [
|
||||||
{"slug": "welcome", "title": "Welcome", "section": "Start here", "file": "welcome.md"},
|
{"slug": "welcome", "title": "Welcome", "section": "Start here", "file": "welcome.md"},
|
||||||
@@ -20,18 +18,8 @@ DOCS_PAGES = [
|
|||||||
{"slug": "join", "title": "Joining", "section": "Start here", "file": "join.md"},
|
{"slug": "join", "title": "Joining", "section": "Start here", "file": "join.md"},
|
||||||
{"slug": "legal", "title": "Terms and privacy", "section": "Start here", "file": "legal.md"},
|
{"slug": "legal", "title": "Terms and privacy", "section": "Start here", "file": "legal.md"},
|
||||||
{"slug": "api", "title": "API and authentication", "section": "Building with the API", "file": "api.md"},
|
{"slug": "api", "title": "API and authentication", "section": "Building with the API", "file": "api.md"},
|
||||||
{"slug": "architecture", "title": "Architecture", "section": "Contributing and internals", "file": "architecture.md"},
|
|
||||||
{"slug": "frontend", "title": "Frontend and components", "section": "Contributing and internals", "file": "frontend.md"},
|
|
||||||
{"slug": "admin", "title": "Admin and services", "section": "Admin", "file": "admin.md", "admin": True},
|
{"slug": "admin", "title": "Admin and services", "section": "Admin", "file": "admin.md", "admin": True},
|
||||||
{"slug": "backups", "title": "Backups and maintenance", "section": "Admin", "file": "backups.md", "admin": True},
|
{"slug": "backups", "title": "Backups and maintenance", "section": "Admin", "file": "backups.md", "admin": True},
|
||||||
] + [
|
|
||||||
{
|
|
||||||
"slug": f"component-{name}",
|
|
||||||
"title": f"dp-{name}",
|
|
||||||
"section": "Contributing and internals",
|
|
||||||
"file": f"component-{name}.md",
|
|
||||||
}
|
|
||||||
for name in COMPONENTS
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ LEGACY_PATHS = {
|
|||||||
"/docs/schrijven": "/docs/writing",
|
"/docs/schrijven": "/docs/writing",
|
||||||
"/docs/binnen": "/docs/join",
|
"/docs/binnen": "/docs/join",
|
||||||
"/docs/juridisch": "/docs/legal",
|
"/docs/juridisch": "/docs/legal",
|
||||||
"/docs/architectuur": "/docs/architecture",
|
"/docs/architectuur": "/docs/welcome",
|
||||||
"/docs/beheer": "/docs/admin",
|
"/docs/beheer": "/docs/admin",
|
||||||
"/docs/api/inhoud": "/docs/api/content",
|
"/docs/api/inhoud": "/docs/api/content",
|
||||||
"/docs/api/binnen": "/docs/api/join",
|
"/docs/api/binnen": "/docs/api/join",
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# Architecture
|
|
||||||
|
|
||||||
FastAPI with Jinja2, rendered on the server. SQLite through `dataset`, synchronous and deliberately without a threadpool. Sessions with PBKDF2-SHA256 passwords.
|
|
||||||
|
|
||||||
## Layers
|
|
||||||
|
|
||||||
- `molodetz/database/`: one file per subject, always import from the package root.
|
|
||||||
- `molodetz/routers/`: mirrors the URL path.
|
|
||||||
- `molodetz/services/`: background services under one supervisor with a file lock.
|
|
||||||
- `molodetz/templates/`: one Jinja environment in `templating.py`.
|
|
||||||
|
|
||||||
## Deleting
|
|
||||||
|
|
||||||
Everything is soft deleted with `deleted_at` and `deleted_by`. Only cleanup jobs delete for real.
|
|
||||||
|
|
||||||
## Static files
|
|
||||||
|
|
||||||
Assets go through `static_url()`, which versions them under `/static/v<version>/`. Those are immutably cacheable for a year.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-avatar
|
|
||||||
|
|
||||||
Shows a deterministic SVG avatar plus a presence dot. Attributes `seed`, `size`, `uid`.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-chat
|
|
||||||
|
|
||||||
Simple log with an input line. Emits a `dp-chat-send` event.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-code
|
|
||||||
|
|
||||||
Highlights a code block with highlight.js and adds a Copy button.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-content
|
|
||||||
|
|
||||||
Renders live markdown on the client through marked, then DOMPurify. Only for live content, such as the editor preview.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-context-menu
|
|
||||||
|
|
||||||
Small context menu with buttons, positioned at the cursor.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-dialog
|
|
||||||
|
|
||||||
Confirmation dialog. Forms with `data-confirm` go through it.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-lightbox
|
|
||||||
|
|
||||||
Full screen view for images with `data-lightbox`. Escape or a click closes it.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-title
|
|
||||||
|
|
||||||
Inline variant of dp-content for titles.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-toast
|
|
||||||
|
|
||||||
Host for short notices. Use `Toast.flash(el, message)` or `app.toast(message)`.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# dp-upload
|
|
||||||
|
|
||||||
Drop zone for files. Emits a `dp-files` event with the chosen files.
|
|
||||||
|
|
||||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Frontend and components
|
|
||||||
|
|
||||||
ES6 modules, one class per file, no framework and no bundler. `Application.js` creates all singletons and sets `window.app`.
|
|
||||||
|
|
||||||
Components are custom elements with the `dp-` prefix, without shadow DOM. See the component pages in the sidebar.
|
|
||||||
|
|
||||||
Client rendering with marked and DOMPurify is only for live content: the preview in the editor. Published posts are rendered on the server.
|
|
||||||
@@ -12,4 +12,4 @@ Molodetz is a quiet blog roll. Notes about the work, finishing it, and judgement
|
|||||||
|
|
||||||
## Where to start
|
## Where to start
|
||||||
|
|
||||||
Read [Writing on the roll](/docs/writing) for the content, [API and authentication](/docs/api) for integrations, and [Architecture](/docs/architecture) if you want to know how it is built.
|
Read [Writing on the roll](/docs/writing) for the content, and [API and authentication](/docs/api) for integrations.
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "molodetz"
|
name = "molodetz"
|
||||||
version = "1.0.15"
|
version = "1.0.16"
|
||||||
description = "Molodetz, a calm community blog roll."
|
description = "Molodetz, a calm community blog roll."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# retoor <retoor@molodetz.nl>
|
||||||
|
import re
|
||||||
|
|
||||||
|
from molodetz.docs_prose import DOCS_PAGES, PROSE_DIR, SECTIONS
|
||||||
|
|
||||||
|
BANNED_SECTION = "Contributing and internals"
|
||||||
|
BANNED_TITLES = {
|
||||||
|
"Architecture",
|
||||||
|
"Frontend and components",
|
||||||
|
"dp-avatar",
|
||||||
|
"dp-code",
|
||||||
|
"dp-content",
|
||||||
|
"dp-title",
|
||||||
|
"dp-toast",
|
||||||
|
"dp-dialog",
|
||||||
|
"dp-context-menu",
|
||||||
|
"dp-upload",
|
||||||
|
"dp-lightbox",
|
||||||
|
"dp-chat",
|
||||||
|
}
|
||||||
|
BANNED_SLUGS = {
|
||||||
|
"architecture",
|
||||||
|
"frontend",
|
||||||
|
"component-avatar",
|
||||||
|
"component-code",
|
||||||
|
"component-content",
|
||||||
|
"component-title",
|
||||||
|
"component-toast",
|
||||||
|
"component-dialog",
|
||||||
|
"component-context-menu",
|
||||||
|
"component-upload",
|
||||||
|
"component-lightbox",
|
||||||
|
"component-chat",
|
||||||
|
}
|
||||||
|
BANNED_FILES = {
|
||||||
|
"architecture.md",
|
||||||
|
"frontend.md",
|
||||||
|
*[
|
||||||
|
f"component-{name}.md"
|
||||||
|
for name in (
|
||||||
|
"avatar",
|
||||||
|
"code",
|
||||||
|
"content",
|
||||||
|
"title",
|
||||||
|
"toast",
|
||||||
|
"dialog",
|
||||||
|
"context-menu",
|
||||||
|
"upload",
|
||||||
|
"lightbox",
|
||||||
|
"chat",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _docs_surfaces(html):
|
||||||
|
sidebar = re.search(r'<aside class="docs-sidebar">(.*?)</aside>', html, re.S)
|
||||||
|
content = re.search(r'<article class="docs-content[^"]*">(.*?)</article>', html, re.S)
|
||||||
|
return (sidebar.group(1) if sidebar else ""), (content.group(1) if content else "")
|
||||||
|
|
||||||
|
|
||||||
|
def test_docs_registry_excludes_removed_internals():
|
||||||
|
assert BANNED_SECTION not in SECTIONS
|
||||||
|
titles = {page["title"] for page in DOCS_PAGES}
|
||||||
|
slugs = {page["slug"] for page in DOCS_PAGES}
|
||||||
|
sections = {page["section"] for page in DOCS_PAGES}
|
||||||
|
assert not titles & BANNED_TITLES
|
||||||
|
assert not slugs & BANNED_SLUGS
|
||||||
|
assert BANNED_SECTION not in sections
|
||||||
|
for name in BANNED_FILES:
|
||||||
|
assert not (PROSE_DIR / name).exists(), name
|
||||||
|
|
||||||
|
|
||||||
|
def test_served_docs_hide_removed_internals(anon, admin):
|
||||||
|
banned_hrefs = {f"/docs/{slug}" for slug in BANNED_SLUGS}
|
||||||
|
for client in (anon, admin):
|
||||||
|
for path in ("/docs", "/docs/welcome", "/docs/api"):
|
||||||
|
html = client.get(path).text
|
||||||
|
sidebar, content = _docs_surfaces(html)
|
||||||
|
surface = f"{sidebar}\n{content}"
|
||||||
|
assert BANNED_SECTION not in surface, path
|
||||||
|
for title in BANNED_TITLES:
|
||||||
|
assert title not in surface, (path, title)
|
||||||
|
for href in banned_hrefs:
|
||||||
|
assert href not in surface, (path, href)
|
||||||
|
for slug in sorted(BANNED_SLUGS):
|
||||||
|
assert anon.get(f"/docs/{slug}").status_code == 404, slug
|
||||||
+1
-1
@@ -14,7 +14,7 @@ REDIRECTS = [
|
|||||||
("/docs/schrijven", "/docs/writing"),
|
("/docs/schrijven", "/docs/writing"),
|
||||||
("/docs/binnen", "/docs/join"),
|
("/docs/binnen", "/docs/join"),
|
||||||
("/docs/juridisch", "/docs/legal"),
|
("/docs/juridisch", "/docs/legal"),
|
||||||
("/docs/architectuur", "/docs/architecture"),
|
("/docs/architectuur", "/docs/welcome"),
|
||||||
("/docs/api/inhoud", "/docs/api/content"),
|
("/docs/api/inhoud", "/docs/api/content"),
|
||||||
("/docs/api/binnen", "/docs/api/join"),
|
("/docs/api/binnen", "/docs/api/join"),
|
||||||
]
|
]
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
# retoor <retoor@molodetz.nl>
|
# retoor <retoor@molodetz.nl>
|
||||||
from tests.conftest import assert_no_horizontal_overflow, goto_ready
|
from tests.conftest import assert_no_horizontal_overflow, goto_ready
|
||||||
|
|
||||||
PUBLIC_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/docs", "/docs/welcome", "/docs/api/content", "/docs/component-code", "/terms", "/privacy"]
|
PUBLIC_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/docs", "/docs/welcome", "/docs/api/content", "/terms", "/privacy"]
|
||||||
|
|
||||||
|
|
||||||
def test_home_renders_without_errors(page, app_server):
|
def test_home_renders_without_errors(page, app_server):
|
||||||
|
|||||||
Reference in New Issue
Block a user