···258258 # The one shared calendar (configs/radicale.nix): lass's own events, the
259259 # book.lassul.us requests and bookings, and anything Hermes adds. Hermes
260260 # authenticates as its own radicale user, which may only touch this
261261- # collection. Bookings are mirrored from book's database, so they are
262262- # managed through book's admin links rather than edited in CalDAV.
261261+ # collection. Booking events are read back by book, so deleting, moving
262262+ # or confirming them in CalDAV manages the booking (tools/book).
263263 hermesHomeFiles."skills/calendar/SKILL.md" = ''
264264 ---
265265 name: calendar
···334334335335 ## Booking requests and bookings (book.lassul.us)
336336337337- Events whose UID ends in `@book.lassul.us` belong to the booking page.
338338- Never PUT or DELETE them: the booking page owns them, rewrites them on
339339- every change, and only it mails the guest.
337337+ Events whose UID ends in `@book.lassul.us` come from the booking page.
338338+ It reads them back every minute (for bookings that have not started
339339+ yet) and mails the guest about what changed, so editing them is how
340340+ bookings are managed:
340341341342 - Pending request: `STATUS:TENTATIVE`, SUMMARY starts with `? `.
342343 - Booked: `STATUS:CONFIRMED`.
343344 - The DESCRIPTION holds the guest (`Name <email>`), their note, and as
344345 its last line the admin link `https://book.lassul.us/a/<token>`.
345346346346- Act on a booking only when the user decided to, by POSTing to its
347347- admin link (an optional `message` is mailed to the guest):
347347+ | Calendar edit | Effect, guest mail |
348348+ | --- | --- |
349349+ | DELETE a booked event (or set `STATUS:CANCELLED`) | cancelled, guest gets a cancellation |
350350+ | DELETE a pending request | declined, guest gets a decline |
351351+ | Change DTSTART/DTEND | rescheduled; a booked guest gets the updated invitation |
352352+ | Set a pending request to `STATUS:CONFIRMED` | approved, guest gets the invitation |
353353+354354+ Use If-Match as for your own events. The booking page rewrites SUMMARY
355355+ and DESCRIPTION itself; edits to them are not kept. Act on a booking
356356+ only when the user decided to.
357357+358358+ To send the guest a personal message with the decision, use the admin
359359+ link instead (an optional `message` is mailed along):
348360349361 ```sh
350362 curl -sS -o /dev/null -w '%{http_code}\n' -X POST \
···352364 'https://book.lassul.us/a/<token>/approve' # or /decline, /cancel
353365 ```
354366355355- A 303 means it worked: approve turns the event CONFIRMED, decline and
356356- cancel remove it from the calendar. `GET` on the admin link shows the
357357- request's current state. Treat admin links as secrets: never paste one
358358- into a chat unless the user asks for it.
367367+ A 303 means it worked. `GET` on the admin link shows the request's
368368+ current state. Treat admin links as secrets: never paste one into a
369369+ chat unless the user asks for it.
359370 '';
360371361372 # Non-secret connection + SECURITY gate. Invites are auto-accepted and that