This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
@@ -24,13 +24,58 @@ from typing import Any
|
|||||||
from urllib.parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parent
|
def looks_like_content_root(path: Path) -> bool:
|
||||||
|
return (path / "authoring_server.py").exists() and (
|
||||||
|
(path / "blogs").exists()
|
||||||
|
or (path / "posts").exists()
|
||||||
|
or (path / "lima").exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_root() -> Path:
|
||||||
|
env_root = os.environ.get("AUTHOR_ROOT")
|
||||||
|
if env_root:
|
||||||
|
return Path(env_root).expanduser().resolve()
|
||||||
|
candidates = [
|
||||||
|
Path.cwd(),
|
||||||
|
Path(__file__).resolve().parent,
|
||||||
|
]
|
||||||
|
workspace = os.environ.get("GITHUB_WORKSPACE")
|
||||||
|
if workspace:
|
||||||
|
candidates.insert(0, Path(workspace))
|
||||||
|
for base in list(candidates):
|
||||||
|
candidates.extend(base.parents)
|
||||||
|
seen = set()
|
||||||
|
for candidate in candidates:
|
||||||
|
resolved = candidate.expanduser().resolve()
|
||||||
|
if resolved in seen:
|
||||||
|
continue
|
||||||
|
seen.add(resolved)
|
||||||
|
if looks_like_content_root(resolved):
|
||||||
|
return resolved
|
||||||
|
return Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = resolve_root()
|
||||||
BLOGS_DIR = ROOT / "blogs"
|
BLOGS_DIR = ROOT / "blogs"
|
||||||
POSTS_DIR = ROOT / "posts"
|
POSTS_DIR = ROOT / "posts"
|
||||||
LIMA_DIR = ROOT / "lima"
|
LIMA_DIR = ROOT / "lima"
|
||||||
HZONE_ASSETS_DIR = ROOT / "assets" / "images" / "hzone"
|
HZONE_ASSETS_DIR = ROOT / "assets" / "images" / "hzone"
|
||||||
|
EXCLUDED_CONTENT_DIR_NAMES = {
|
||||||
|
".agents",
|
||||||
|
".codex",
|
||||||
|
".git",
|
||||||
|
".packages",
|
||||||
|
".venv",
|
||||||
|
"__pycache__",
|
||||||
|
"assets",
|
||||||
|
"backups",
|
||||||
|
"output",
|
||||||
|
"tags",
|
||||||
|
}
|
||||||
GENERATED_ORG_NAMES = {
|
GENERATED_ORG_NAMES = {
|
||||||
"blogs-list.org",
|
"blogs-list.org",
|
||||||
|
"books-list.org",
|
||||||
"posts-list.org",
|
"posts-list.org",
|
||||||
"career-list.org",
|
"career-list.org",
|
||||||
"sitemap.org",
|
"sitemap.org",
|
||||||
@@ -249,12 +294,16 @@ def safe_relative_path(path: str) -> Path:
|
|||||||
full = (ROOT / rel).resolve()
|
full = (ROOT / rel).resolve()
|
||||||
if not full.is_relative_to(ROOT):
|
if not full.is_relative_to(ROOT):
|
||||||
raise ValueError("Path must stay inside this repository.")
|
raise ValueError("Path must stay inside this repository.")
|
||||||
if full.suffix == ".org" and (full.is_relative_to(BLOGS_DIR) or full.is_relative_to(POSTS_DIR)):
|
if full.name in GENERATED_CONTENT_NAMES or "sync-conflict" in full.name:
|
||||||
|
raise ValueError("Generated and sync-conflict files are not editable here.")
|
||||||
|
rel_parts = full.relative_to(ROOT).parts
|
||||||
|
if any(part in EXCLUDED_CONTENT_DIR_NAMES for part in rel_parts):
|
||||||
|
raise ValueError("This path is outside the editable content folders.")
|
||||||
|
if full.suffix == ".org":
|
||||||
return full
|
return full
|
||||||
if full.suffix == ".md" and full.is_relative_to(LIMA_DIR):
|
if full.suffix == ".md" and full.is_relative_to(LIMA_DIR):
|
||||||
return full
|
return full
|
||||||
raise ValueError("Only .org files under blogs/posts and .md files under lima can be edited here.")
|
raise ValueError("Only .org content files and .md files under lima can be edited here.")
|
||||||
return full
|
|
||||||
|
|
||||||
|
|
||||||
def safe_target_path(path: str, slug: str, page_type: str) -> Path:
|
def safe_target_path(path: str, slug: str, page_type: str) -> Path:
|
||||||
@@ -310,7 +359,12 @@ def read_page(path: Path) -> ContentPage:
|
|||||||
in_header = False
|
in_header = False
|
||||||
body_lines.append(line)
|
body_lines.append(line)
|
||||||
rel = path.relative_to(ROOT).as_posix()
|
rel = path.relative_to(ROOT).as_posix()
|
||||||
page_type = "blog" if path.is_relative_to(BLOGS_DIR) else "post"
|
if path.is_relative_to(BLOGS_DIR):
|
||||||
|
page_type = "blog"
|
||||||
|
elif path.is_relative_to(POSTS_DIR):
|
||||||
|
page_type = "post"
|
||||||
|
else:
|
||||||
|
page_type = "page"
|
||||||
slug = meta.get("SLUG") or path.stem
|
slug = meta.get("SLUG") or path.stem
|
||||||
tags = normalise_tags(meta.get("FILETAGS", ""))
|
tags = normalise_tags(meta.get("FILETAGS", ""))
|
||||||
return ContentPage(
|
return ContentPage(
|
||||||
@@ -346,14 +400,15 @@ def page_to_dict(page: ContentPage) -> dict[str, Any]:
|
|||||||
|
|
||||||
def list_pages() -> list[dict[str, Any]]:
|
def list_pages() -> list[dict[str, Any]]:
|
||||||
pages = []
|
pages = []
|
||||||
for base, page_type, extension in (
|
org_paths = []
|
||||||
(BLOGS_DIR, "blog", "*.org"),
|
if ROOT.exists():
|
||||||
(POSTS_DIR, "post", "*.org"),
|
for path in ROOT.rglob("*.org"):
|
||||||
(LIMA_DIR, "lima", "*.md"),
|
rel_parts = path.relative_to(ROOT).parts
|
||||||
):
|
if any(part in EXCLUDED_CONTENT_DIR_NAMES for part in rel_parts):
|
||||||
if not base.exists():
|
|
||||||
continue
|
continue
|
||||||
for path in sorted(base.rglob(extension)):
|
org_paths.append(path)
|
||||||
|
md_paths = list(LIMA_DIR.rglob("*.md")) if LIMA_DIR.exists() else []
|
||||||
|
for path in sorted(org_paths + md_paths):
|
||||||
if path.name in GENERATED_CONTENT_NAMES or "sync-conflict" in path.name:
|
if path.name in GENERATED_CONTENT_NAMES or "sync-conflict" in path.name:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
@@ -364,7 +419,7 @@ def list_pages() -> list[dict[str, Any]]:
|
|||||||
pages.append(
|
pages.append(
|
||||||
{
|
{
|
||||||
"path": page.path,
|
"path": page.path,
|
||||||
"pageType": page_type,
|
"pageType": page.page_type,
|
||||||
"title": page.title,
|
"title": page.title,
|
||||||
"slug": page.slug,
|
"slug": page.slug,
|
||||||
"tags": page.tags,
|
"tags": page.tags,
|
||||||
@@ -396,7 +451,9 @@ def target_path(data: dict[str, Any], existing_path: str | None) -> Path:
|
|||||||
return folder / f"{slug}.org"
|
return folder / f"{slug}.org"
|
||||||
if page_type == "lima":
|
if page_type == "lima":
|
||||||
return LIMA_DIR / f"{slug}.md"
|
return LIMA_DIR / f"{slug}.md"
|
||||||
raise ValueError("pageType must be blog, post, or lima.")
|
if page_type == "page":
|
||||||
|
return ROOT / f"{slug}.org"
|
||||||
|
raise ValueError("pageType must be blog, post, page, or lima.")
|
||||||
|
|
||||||
|
|
||||||
def render_markdown(data: dict[str, Any]) -> str:
|
def render_markdown(data: dict[str, Any]) -> str:
|
||||||
@@ -669,9 +726,10 @@ APP_HTML = r"""<!doctype html>
|
|||||||
<div class="filters">
|
<div class="filters">
|
||||||
<input id="search" type="search" placeholder="Filter pages" />
|
<input id="search" type="search" placeholder="Filter pages" />
|
||||||
<select id="typeFilter">
|
<select id="typeFilter">
|
||||||
<option value="">Blogs and posts</option>
|
<option value="">All files</option>
|
||||||
<option value="blog">Blogs</option>
|
<option value="blog">Blogs</option>
|
||||||
<option value="post">Posts</option>
|
<option value="post">Posts</option>
|
||||||
|
<option value="page">Pages</option>
|
||||||
<option value="lima">Lima</option>
|
<option value="lima">Lima</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -688,6 +746,7 @@ APP_HTML = r"""<!doctype html>
|
|||||||
<select name="pageType">
|
<select name="pageType">
|
||||||
<option value="blog">Blog</option>
|
<option value="blog">Blog</option>
|
||||||
<option value="post">Post</option>
|
<option value="post">Post</option>
|
||||||
|
<option value="page">Page</option>
|
||||||
<option value="lima">Lima</option>
|
<option value="lima">Lima</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -819,11 +878,14 @@ APP_HTML = r"""<!doctype html>
|
|||||||
const query = $("#search").value.toLowerCase();
|
const query = $("#search").value.toLowerCase();
|
||||||
const type = $("#typeFilter").value;
|
const type = $("#typeFilter").value;
|
||||||
pagesBox.innerHTML = "";
|
pagesBox.innerHTML = "";
|
||||||
state.pages
|
const matches = state.pages
|
||||||
.filter((page) => (!type || page.pageType === type))
|
.filter((page) => (!type || page.pageType === type))
|
||||||
.filter((page) => `${page.title} ${page.path} ${page.tags.join(" ")}`.toLowerCase().includes(query))
|
.filter((page) => `${page.title} ${page.path} ${page.tags.join(" ")}`.toLowerCase().includes(query))
|
||||||
.slice(0, 120)
|
.slice(0, 120);
|
||||||
.forEach((page) => {
|
if (!matches.length) {
|
||||||
|
pagesBox.innerHTML = `<div class="queue-item"><span>No files matched.</span></div>`;
|
||||||
|
}
|
||||||
|
matches.forEach((page) => {
|
||||||
const btn = document.createElement("button");
|
const btn = document.createElement("button");
|
||||||
btn.type = "button";
|
btn.type = "button";
|
||||||
btn.className = "page-item";
|
btn.className = "page-item";
|
||||||
@@ -938,8 +1000,12 @@ APP_HTML = r"""<!doctype html>
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function refreshPages() {
|
async function refreshPages() {
|
||||||
|
try {
|
||||||
state.pages = await api("/api/pages");
|
state.pages = await api("/api/pages");
|
||||||
renderPages();
|
renderPages();
|
||||||
|
} catch (err) {
|
||||||
|
pagesBox.innerHTML = `<div class="queue-item"><span>${html(err.message)}</span></div>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshBuild() {
|
async function refreshBuild() {
|
||||||
@@ -1002,6 +1068,10 @@ APP_HTML = r"""<!doctype html>
|
|||||||
editor.targetPath.value = `lima/${slug}.md`;
|
editor.targetPath.value = `lima/${slug}.md`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (editor.pageType.value === "page") {
|
||||||
|
editor.targetPath.value = `${slug}.org`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (editor.pageType.value === "post") {
|
if (editor.pageType.value === "post") {
|
||||||
const section = slugify(editor.section.value || "");
|
const section = slugify(editor.section.value || "");
|
||||||
editor.targetPath.value = section === "untitled" ? `posts/${slug}.org` : `posts/${section}/${slug}.org`;
|
editor.targetPath.value = section === "untitled" ? `posts/${slug}.org` : `posts/${section}/${slug}.org`;
|
||||||
@@ -1299,6 +1369,7 @@ def main() -> None:
|
|||||||
port = int(os.environ.get("AUTHOR_PORT", "8765"))
|
port = int(os.environ.get("AUTHOR_PORT", "8765"))
|
||||||
server = ThreadingHTTPServer(("127.0.0.1", port), Handler)
|
server = ThreadingHTTPServer(("127.0.0.1", port), Handler)
|
||||||
print(f"Authoring UI running at http://127.0.0.1:{port}")
|
print(f"Authoring UI running at http://127.0.0.1:{port}")
|
||||||
|
print(f"Content root: {ROOT}")
|
||||||
print("Press Ctrl-C to stop.")
|
print("Press Ctrl-C to stop.")
|
||||||
try:
|
try:
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
|
|||||||
10
blogs/2026/05-may/using-codex-07-05-26.org
Normal file
10
blogs/2026/05-may/using-codex-07-05-26.org
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#+TITLE: Using Codex
|
||||||
|
#+OPTIONS: num:nil
|
||||||
|
#+DATE: <2026-05-07 Thu 16:12>
|
||||||
|
#+filetags: :life:
|
||||||
|
#+COMMENTS: t
|
||||||
|
#+SLUG: using-codex-07-05-26
|
||||||
|
|
||||||
|
Recently started to play around with codex, installing the CLI, and having it do a few things I've been wanting to work on. So far it's exceeded my expectations. This page [[https://author.zainezq.com][Author]] has been created by Codex using a single python script.
|
||||||
|
|
||||||
|
I also had it create a powershell script to do an analysis of the build pipelines hosted in gitea.
|
||||||
@@ -6,6 +6,7 @@ See the categories: @@html:<a href="../home/categories.html">Categories</a>@@
|
|||||||
* 2026
|
* 2026
|
||||||
|
|
||||||
** May 2026
|
** May 2026
|
||||||
|
- [[file:2026/05-may/using-codex-07-05-26.org][Using Codex]] @@html:<span class="post-date">07-05-2026 16:12</span>@@ @@html:<a href="/tags/life.html"><span class="post-tag">life</span></a>@@
|
||||||
- [[file:2026/05-may/03-05-week-review.org][[03-05-2026] - Weekly Review]] @@html:<span class="post-date">03-05-2026 12:00</span>@@ @@html:<a href="/tags/review.html"><span class="post-tag">review</span></a>@@
|
- [[file:2026/05-may/03-05-week-review.org][[03-05-2026] - Weekly Review]] @@html:<span class="post-date">03-05-2026 12:00</span>@@ @@html:<a href="/tags/review.html"><span class="post-tag">review</span></a>@@
|
||||||
- [[file:2026/05-may/sun-soak-01-05.org][Soaking in the sun]] @@html:<span class="post-date">01-05-2026 12:27</span>@@ @@html:<a href="/tags/life.html"><span class="post-tag">life</span></a>@@
|
- [[file:2026/05-may/sun-soak-01-05.org][Soaking in the sun]] @@html:<span class="post-date">01-05-2026 12:27</span>@@ @@html:<a href="/tags/life.html"><span class="post-tag">life</span></a>@@
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
- [[file:../tags/insights.org][@@html:<span class="post-tag">insights</span>@@]] (4)
|
- [[file:../tags/insights.org][@@html:<span class="post-tag">insights</span>@@]] (4)
|
||||||
- [[file:../tags/introduction.org][@@html:<span class="post-tag">introduction</span>@@]] (3)
|
- [[file:../tags/introduction.org][@@html:<span class="post-tag">introduction</span>@@]] (3)
|
||||||
- [[file:../tags/learning.org][@@html:<span class="post-tag">learning</span>@@]] (16)
|
- [[file:../tags/learning.org][@@html:<span class="post-tag">learning</span>@@]] (16)
|
||||||
- [[file:../tags/life.org][@@html:<span class="post-tag">life</span>@@]] (28)
|
- [[file:../tags/life.org][@@html:<span class="post-tag">life</span>@@]] (29)
|
||||||
- [[file:../tags/maths.org][@@html:<span class="post-tag">maths</span>@@]] (1)
|
- [[file:../tags/maths.org][@@html:<span class="post-tag">maths</span>@@]] (1)
|
||||||
- [[file:../tags/notes.org][@@html:<span class="post-tag">notes</span>@@]] (17)
|
- [[file:../tags/notes.org][@@html:<span class="post-tag">notes</span>@@]] (17)
|
||||||
- [[file:../tags/reading.org][@@html:<span class="post-tag">reading</span>@@]] (1)
|
- [[file:../tags/reading.org][@@html:<span class="post-tag">reading</span>@@]] (1)
|
||||||
|
|||||||
@@ -9,6 +9,3 @@ I made quite a few changes. It all started when I realised that not everyone kno
|
|||||||
- I probably didn’t explain it as well, but you can create folders and files under the `lima-website` directory. The files must have a `.md` extension at the end (markdown).
|
- I probably didn’t explain it as well, but you can create folders and files under the `lima-website` directory. The files must have a `.md` extension at the end (markdown).
|
||||||
|
|
||||||
- One other thing, a more personal one: what do you think of all this? am i doing too much? am i doing too little? am i overengineering things? am i forcing you to do something you dont wanna do? these little trinkets work for me, but i’m not sure if it would work for someone else, so at any point if you have reservations, let me know okay?
|
- One other thing, a more personal one: what do you think of all this? am i doing too much? am i doing too little? am i overengineering things? am i forcing you to do something you dont wanna do? these little trinkets work for me, but i’m not sure if it would work for someone else, so at any point if you have reservations, let me know okay?
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
See the categories: @@html:<a href="../home/categories.html">Categories</a>@@
|
See the categories: @@html:<a href="../home/categories.html">Categories</a>@@
|
||||||
|
|
||||||
* Posts:
|
* Posts:
|
||||||
- [[file:career/career-list.org][Career List]] @@html:<span class="post-date">07-05-2026 15:52</span>@@
|
- [[file:career/career-list.org][Career List]] @@html:<span class="post-date">07-05-2026 16:21</span>@@
|
||||||
- [[file:posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:<span class="post-date">14-04-2026 16:36</span>@@
|
- [[file:posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:<span class="post-date">14-04-2026 16:36</span>@@
|
||||||
- [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:<span class="post-date">11-03-2026 17:18</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
|
- [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:<span class="post-date">11-03-2026 17:18</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
|
||||||
- [[file:career/javascript.org][Understands the Javascript language]] @@html:<span class="post-date">11-03-2026 16:52</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
|
- [[file:career/javascript.org][Understands the Javascript language]] @@html:<span class="post-date">11-03-2026 16:52</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#+OPTIONS: toc:nil num:nil
|
#+OPTIONS: toc:nil num:nil
|
||||||
|
|
||||||
* Recently Updated (top 26 files)
|
* Recently Updated (top 26 files)
|
||||||
|
- [[file:blogs/2026/05-may/using-codex-07-05-26.org][Using Codex]] @@html:<span class="post-date">2026-05-07 16:12</span>@@
|
||||||
- [[file:blogs/2026/05-may/03-05-week-review.org][[03-05-2026] - Weekly Review]] @@html:<span class="post-date">2026-05-03 12:00</span>@@
|
- [[file:blogs/2026/05-may/03-05-week-review.org][[03-05-2026] - Weekly Review]] @@html:<span class="post-date">2026-05-03 12:00</span>@@
|
||||||
- [[file:blogs/2026/05-may/sun-soak-01-05.org][Soaking in the sun]] @@html:<span class="post-date">2026-05-01 12:27</span>@@
|
- [[file:blogs/2026/05-may/sun-soak-01-05.org][Soaking in the sun]] @@html:<span class="post-date">2026-05-01 12:27</span>@@
|
||||||
- [[file:blogs/2026/04-april/wise-words-29-04.org][Wise Words I need to engrain]] @@html:<span class="post-date">2026-04-29 11:31</span>@@
|
- [[file:blogs/2026/04-april/wise-words-29-04.org][Wise Words I need to engrain]] @@html:<span class="post-date">2026-04-29 11:31</span>@@
|
||||||
@@ -15,7 +16,6 @@
|
|||||||
- [[file:blogs/2026/04-april/16-04-26.org][Rambles]] @@html:<span class="post-date">2026-04-16 16:02</span>@@
|
- [[file:blogs/2026/04-april/16-04-26.org][Rambles]] @@html:<span class="post-date">2026-04-16 16:02</span>@@
|
||||||
- [[file:posts/posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:<span class="post-date">2026-04-14 16:36</span>@@
|
- [[file:posts/posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:<span class="post-date">2026-04-14 16:36</span>@@
|
||||||
- [[file:home/categories.sync-conflict-20260417-233429-VT6366A.org][Categories]] @@html:<span class="post-date">2026-04-14 16:36</span>@@
|
- [[file:home/categories.sync-conflict-20260417-233429-VT6366A.org][Categories]] @@html:<span class="post-date">2026-04-14 16:36</span>@@
|
||||||
- [[file:recently-updated.sync-conflict-20260417-233430-VT6366A.org][Recently Updated]] @@html:<span class="post-date">2026-04-14 16:36</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/comparison-14-04.org][Comparison is the thief of joy]] @@html:<span class="post-date">2026-04-14 09:55</span>@@
|
- [[file:blogs/2026/04-april/comparison-14-04.org][Comparison is the thief of joy]] @@html:<span class="post-date">2026-04-14 09:55</span>@@
|
||||||
- [[file:blogs/2026/04-april/12-04-week-review.org][[12-04-2026] - Weekly Review]] @@html:<span class="post-date">2026-04-12 12:00</span>@@
|
- [[file:blogs/2026/04-april/12-04-week-review.org][[12-04-2026] - Weekly Review]] @@html:<span class="post-date">2026-04-12 12:00</span>@@
|
||||||
- [[file:blogs/2026/04-april/starting-new-rotation-08-04-26.org][Starting new rotation]] @@html:<span class="post-date">2026-04-08 16:15</span>@@
|
- [[file:blogs/2026/04-april/starting-new-rotation-08-04-26.org][Starting new rotation]] @@html:<span class="post-date">2026-04-08 16:15</span>@@
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
#+TITLE: Recently Updated
|
|
||||||
#+OPTIONS: toc:nil num:nil
|
|
||||||
|
|
||||||
* Recently Updated (top 26 files)
|
|
||||||
- [[file:blogs/2026/04-april/comparison-14-04.org][Comparison is the thief of joy]] @@html:<span class="post-date">2026-04-14 09:55</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/12-04-week-review.org][[12-04-2026] - Weekly Review]] @@html:<span class="post-date">2026-04-12 12:00</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/starting-new-rotation-08-04-26.org][Starting new rotation]] @@html:<span class="post-date">2026-04-08 16:15</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/action-plan-07-04-26.org][Action plan to change teams]] @@html:<span class="post-date">2026-04-07 10:04</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/weekly-target-06-04-26.org][[06-04-2026] - Weekly target]] @@html:<span class="post-date">2026-04-06 22:53</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/making-notes-through-org-noter-06-05.org][Making Notes through Org Noter]] @@html:<span class="post-date">2026-04-06 14:30</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/05-04-week-review.org][[05-04-2026] - Weekly Review]] @@html:<span class="post-date">2026-04-05 12:00</span>@@
|
|
||||||
- [[file:blogs/2026/04-april/joining-new-team-meeting-02-04-2026.org][New team meeting]] @@html:<span class="post-date">2026-04-02 16:03</span>@@
|
|
||||||
- [[file:home/wird-tracker.org][Wird Tracker]] @@html:<span class="post-date">2026-04-02 11:17</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/intellectually-challenging-myself-30-03-26.org][Intellectually challenging oneself]] @@html:<span class="post-date">2026-03-31 11:14</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/cooking-dinner-29-03-26.org][Cooking Dinner (num)]] @@html:<span class="post-date">2026-03-30 11:49</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/29-03-week-review.org][[29-03-2026] - Weekly Review]] @@html:<span class="post-date">2026-03-29 12:00</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/training-on-friday-afternoon-27-03-26.org][Training time on Friday afternoon]] @@html:<span class="post-date">2026-03-27 15:09</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/more-thoughts-regarding-changes-26-03-26.org][More thoughts on schedule changes]] @@html:<span class="post-date">2026-03-26 12:33</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/thoughts-on-life-25-03-26.org][Thoughts on life...]] @@html:<span class="post-date">2026-03-25 11:37</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/quick-lunch-24-03.org][Making Lunch QUiCk!!]] @@html:<span class="post-date">2026-03-24 15:30</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/installing-emacs-23-03.org][Installing Emacs on Windows]] @@html:<span class="post-date">2026-03-23 16:47</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/22-03-week-review.org][[22-03-2026] - Weekly Review]] @@html:<span class="post-date">2026-03-22 12:00</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/setting-a-wird-tracker-19-03.org][Setting a Wird Tracker]] @@html:<span class="post-date">2026-03-19 13:15</span>@@
|
|
||||||
- [[file:home/guide/wird-tracker-guide.org][Wird Tracker — Technical Guide]] @@html:<span class="post-date">2026-03-19 12:43</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/fixing-the-dag-18-03.org][DAG fixes]] @@html:<span class="post-date">2026-03-18 15:01</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/feeling-sleepy.org][Feeling extremely sleepy]] @@html:<span class="post-date">2026-03-16 16:18</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/oversleeping-16-03.org][Oversleeping and missing a meeting...]] @@html:<span class="post-date">2026-03-16 11:21</span>@@
|
|
||||||
- [[file:blogs/2026/03-march/15-03-week-review.org][[15-03-2026] - Weekly Review]] @@html:<span class="post-date">2026-03-15 12:00</span>@@
|
|
||||||
- [[file:posts/career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:<span class="post-date">2026-03-11 17:18</span>@@
|
|
||||||
- [[file:posts/career/javascript.org][Understands the Javascript language]] @@html:<span class="post-date">2026-03-11 16:52</span>@@
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#+TITLE: Sitemap
|
#+TITLE: Sitemap
|
||||||
|
|
||||||
- [[file:index.org][Home]]
|
- [[file:index.org][Home]]
|
||||||
- [[file:recently-updated.sync-conflict-20260417-233430-VT6366A.org][Recently Updated]]
|
|
||||||
- [[file:wip.org][Work in progress]]
|
- [[file:wip.org][Work in progress]]
|
||||||
- [[file:recently-updated.org][Recently Updated]]
|
- [[file:recently-updated.org][Recently Updated]]
|
||||||
- tags
|
- tags
|
||||||
@@ -11,14 +10,14 @@
|
|||||||
- [[file:tags/learning.org][Tag: learning]]
|
- [[file:tags/learning.org][Tag: learning]]
|
||||||
- [[file:tags/notes.org][Tag: notes]]
|
- [[file:tags/notes.org][Tag: notes]]
|
||||||
- [[file:tags/review.org][Tag: review]]
|
- [[file:tags/review.org][Tag: review]]
|
||||||
- [[file:tags/life.org][Tag: life]]
|
|
||||||
- [[file:tags/website.org][Tag: website]]
|
- [[file:tags/website.org][Tag: website]]
|
||||||
|
- [[file:tags/life.org][Tag: life]]
|
||||||
|
- [[file:tags/education.org][Tag: education]]
|
||||||
- [[file:tags/update.org][Tag: update]]
|
- [[file:tags/update.org][Tag: update]]
|
||||||
- [[file:tags/insights.org][Tag: insights]]
|
- [[file:tags/insights.org][Tag: insights]]
|
||||||
- [[file:tags/emacs.org][Tag: emacs]]
|
- [[file:tags/emacs.org][Tag: emacs]]
|
||||||
- [[file:tags/education.org][Tag: education]]
|
|
||||||
- [[file:tags/reading.org][Tag: reading]]
|
|
||||||
- [[file:tags/maths.org][Tag: maths]]
|
- [[file:tags/maths.org][Tag: maths]]
|
||||||
|
- [[file:tags/reading.org][Tag: reading]]
|
||||||
- home
|
- home
|
||||||
- [[file:home/countdown.org][Countdown]]
|
- [[file:home/countdown.org][Countdown]]
|
||||||
- [[file:home/contact.org][Contact]]
|
- [[file:home/contact.org][Contact]]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#+OPTIONS: toc:nil num:nil title:nil
|
#+OPTIONS: toc:nil num:nil title:nil
|
||||||
|
|
||||||
* Posts tagged life
|
* Posts tagged life
|
||||||
|
- [[file:../blogs/2026/05-may/using-codex-07-05-26.org][Using Codex]]
|
||||||
- [[file:../blogs/2026/05-may/sun-soak-01-05.org][Soaking in the sun]]
|
- [[file:../blogs/2026/05-may/sun-soak-01-05.org][Soaking in the sun]]
|
||||||
- [[file:../blogs/2026/04-april/wise-words-29-04.org][Wise Words I need to engrain]]
|
- [[file:../blogs/2026/04-april/wise-words-29-04.org][Wise Words I need to engrain]]
|
||||||
- [[file:../blogs/2026/04-april/april-almost-over-28-04.org][April is almost over...]]
|
- [[file:../blogs/2026/04-april/april-almost-over-28-04.org][April is almost over...]]
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ class AuthoringServerTestCase(unittest.TestCase):
|
|||||||
self.blogs = self.root / "blogs"
|
self.blogs = self.root / "blogs"
|
||||||
self.posts = self.root / "posts"
|
self.posts = self.root / "posts"
|
||||||
self.lima = self.root / "lima"
|
self.lima = self.root / "lima"
|
||||||
|
self.home = self.root / "home"
|
||||||
|
self.tags = self.root / "tags"
|
||||||
self.hzone = self.root / "assets" / "images" / "hzone"
|
self.hzone = self.root / "assets" / "images" / "hzone"
|
||||||
self.blogs.mkdir()
|
self.blogs.mkdir()
|
||||||
self.posts.mkdir()
|
self.posts.mkdir()
|
||||||
self.lima.mkdir()
|
self.lima.mkdir()
|
||||||
|
self.home.mkdir()
|
||||||
|
self.tags.mkdir()
|
||||||
|
|
||||||
patches = {
|
patches = {
|
||||||
"ROOT": self.root,
|
"ROOT": self.root,
|
||||||
@@ -71,9 +75,13 @@ class UtilityTests(AuthoringServerTestCase):
|
|||||||
server.safe_relative_path("lima/index.md"),
|
server.safe_relative_path("lima/index.md"),
|
||||||
self.lima / "index.md",
|
self.lima / "index.md",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
server.safe_relative_path("home/notes.org"),
|
||||||
|
self.home / "notes.org",
|
||||||
|
)
|
||||||
|
|
||||||
def test_safe_relative_path_rejects_escapes_and_wrong_locations(self):
|
def test_safe_relative_path_rejects_escapes_and_wrong_locations(self):
|
||||||
for path in ("../secret.org", "/tmp/secret.org", "sitemap.org", "lima/index.org"):
|
for path in ("../secret.org", "/tmp/secret.org", "sitemap.org", "assets/style.org", "tags/life.org"):
|
||||||
with self.subTest(path=path):
|
with self.subTest(path=path):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
server.safe_relative_path(path)
|
server.safe_relative_path(path)
|
||||||
@@ -156,10 +164,12 @@ class PageRenderingTests(AuthoringServerTestCase):
|
|||||||
(self.posts / "posts-list.org").write_text("#+TITLE: Generated\n", encoding="utf-8")
|
(self.posts / "posts-list.org").write_text("#+TITLE: Generated\n", encoding="utf-8")
|
||||||
(self.blogs / "note.sync-conflict-1.org").write_text("#+TITLE: Conflict\n", encoding="utf-8")
|
(self.blogs / "note.sync-conflict-1.org").write_text("#+TITLE: Conflict\n", encoding="utf-8")
|
||||||
(self.lima / "index.md").write_text("# Lima Home\n", encoding="utf-8")
|
(self.lima / "index.md").write_text("# Lima Home\n", encoding="utf-8")
|
||||||
|
(self.home / "notes.org").write_text("#+TITLE: Notes\n", encoding="utf-8")
|
||||||
|
(self.tags / "life.org").write_text("#+TITLE: Tag\n", encoding="utf-8")
|
||||||
|
|
||||||
paths = [page["path"] for page in server.list_pages()]
|
paths = [page["path"] for page in server.list_pages()]
|
||||||
|
|
||||||
self.assertEqual(set(paths), {"blogs/keep.org", "lima/index.md"})
|
self.assertEqual(set(paths), {"blogs/keep.org", "home/notes.org", "lima/index.md"})
|
||||||
|
|
||||||
def test_relative_asset_path_is_calculated_from_lima_page_directory(self):
|
def test_relative_asset_path_is_calculated_from_lima_page_directory(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|||||||
Reference in New Issue
Block a user