Add ICS import/export and shared calendar support to calendar UI

- Combine own and shared calendars into a single /web/calendar month
  view, each event colored per its source calendar.
- New event creation now uses a calendar <select> (only writable
  calendars offered); editing keeps the event's original calendar fixed.
- Shared calendars use an "owner~name" reference in URLs, resolved via
  resolveCalRef which also enforces read/write permissions from
  calendar_shares (read-only shares can view/export but not edit/delete).
- Add per-calendar ICS export (single event and export-all) and import,
  splitting multi-VEVENT uploads into individual stored objects while
  preserving VTIMEZONE definitions and source VERSION/PRODID.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-08-20 18:58:04 +02:00
co-authored by Copilot
parent cd2cfa6c06
commit adabfd22ca
5 changed files with 1071 additions and 559 deletions
+7 -5
View File
@@ -54,11 +54,13 @@ func (s *Server) Handler(staticFS http.FileSystem) http.Handler {
mux.HandleFunc("/contacts/{book}/{id}/edit", s.requireLogin(s.handleContactEdit))
mux.HandleFunc("/contacts/{book}/{id}/delete", s.requireLogin(s.handleContactDelete))
mux.HandleFunc("/contacts/{book}/{id}/export", s.requireLogin(s.handleContactExportOne))
mux.HandleFunc("/calendar", s.requireLogin(s.handleCalendarsHome))
mux.HandleFunc("/calendar/{cal}", s.requireLogin(s.handleCalendarMonth))
mux.HandleFunc("/calendar/{cal}/new", s.requireLogin(s.handleEventNew))
mux.HandleFunc("/calendar/{cal}/{id}/edit", s.requireLogin(s.handleEventEdit))
mux.HandleFunc("/calendar/{cal}/{id}/delete", s.requireLogin(s.handleEventDelete))
mux.HandleFunc("/calendar", s.requireLogin(s.handleCalendarMonth))
mux.HandleFunc("/calendar/new", s.requireLogin(s.handleEventNew))
mux.HandleFunc("/calendar/{ref}/import", s.requireLogin(s.handleCalendarImport))
mux.HandleFunc("/calendar/{ref}/export", s.requireLogin(s.handleCalendarExportAll))
mux.HandleFunc("/calendar/{ref}/{id}/edit", s.requireLogin(s.handleEventEdit))
mux.HandleFunc("/calendar/{ref}/{id}/delete", s.requireLogin(s.handleEventDelete))
mux.HandleFunc("/calendar/{ref}/{id}/export", s.requireLogin(s.handleEventExportOne))
return mux
}