m's CalDAV server (dav.msbls.de, SabreDAV) now feeds projax via a thin
read-only-plus-create-on-demand integration. No background sync; tasks
fetched live on detail-page render.
New caldav/ package
- ListCalendars (PROPFIND Depth: 1, filters non-calendar collections)
- ListTodos (REPORT calendar-query for VTODO; hand-rolled iCalendar
parser for UID/SUMMARY/STATUS/DUE/PRIORITY/LAST-MODIFIED — RFC 5545
line-folding aware)
- CreateCalendar (MKCALENDAR, 405 → ErrCalendarExists for the "link
instead" branch)
- httptest-stubbed tests cover all four paths.
Store
- ItemLink shape + LinksByType / LinksByRefType / AddLink / DeleteLink.
AddLink upserts on (item_id, ref_type, ref_id, rel) so re-linking the
same calendar is idempotent.
Web
- GET /admin/caldav — discovery + auto-suggested matches + manual
linker. Suggestion = lowercased displayname == projax slug or title.
- POST /admin/caldav/link — insert item_links row.
- POST /admin/caldav/unlink — delete by link id.
- POST /i/{path}/caldav/create — MKCALENDAR at <base>/<slug>/, then
AddLink. On 405 (already exists), fall back to link-only.
- Detail page Tasks section: per-calendar block with open VTODOs +
collapsed completed (30d window). Errors per calendar logged and
skipped, so one bad calendar does not blank the page.
- nav adds /admin/caldav link.
main.go
- DAV_URL + DAV_USER + DAV_PASSWORD optional. Missing DAV_URL → CalDAV
off (admin page renders "not configured" notice). DAV_URL set but
user/pass missing → fail fast at boot.
docs/design.md gains §5 documenting the integration shape.
deploy/dokploy.yaml lists the two new secrets + the env var.
Phase 2.b (writeback / two-way / background sync) is parked.
25 lines
718 B
Cheetah
25 lines
718 B
Cheetah
{{define "layout"}}<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>{{.Title}} — projax</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
<script src="https://unpkg.com/htmx.org@1.9.12" integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2" crossorigin="anonymous"></script>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<nav>
|
|
<a href="/" class="brand">projax</a>
|
|
<a href="/admin/classify">classify orphans</a>
|
|
<a href="/admin/caldav">caldav</a>
|
|
<form method="post" action="/logout" class="logout-form">
|
|
<button type="submit" class="logout-btn">sign out</button>
|
|
</form>
|
|
</nav>
|
|
</header>
|
|
<main>
|
|
{{template "content" .}}
|
|
</main>
|
|
</body>
|
|
</html>{{end}}
|