feat(web): show ICS subscription events in detail view
This commit is contained in:
+22
-26
@@ -1,8 +1,6 @@
|
||||
package caldav
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -13,6 +11,7 @@ import (
|
||||
"github.com/emersion/go-webdav/caldav"
|
||||
|
||||
"git.arnef.de/arnef/nidus/internal/db"
|
||||
"git.arnef.de/arnef/nidus/internal/icssub"
|
||||
)
|
||||
|
||||
// defaultICSColor is the display color for an ICS/webcal subscription
|
||||
@@ -32,8 +31,9 @@ func (b *Backend) icsSubscriptionCalendarMeta(owner string, sub db.ICSSubscripti
|
||||
}
|
||||
|
||||
// icsObjectUID returns the UID a fetched VEVENT should be addressed by:
|
||||
// its own UID property if it has one, otherwise a stable hash of its
|
||||
// position so it still round-trips consistently between requests.
|
||||
// its own UID property if it has one, otherwise a placeholder derived from
|
||||
// the object ID (so the event still has a *unique* UID in the returned
|
||||
// VCALENDAR).
|
||||
func icsObjectUID(ev ical.Event, fallback string) string {
|
||||
if p := ev.Props.Get(ical.PropUID); p != nil && p.Value != "" {
|
||||
return p.Value
|
||||
@@ -41,16 +41,11 @@ func icsObjectUID(ev ical.Event, fallback string) string {
|
||||
return fallback
|
||||
}
|
||||
|
||||
// icsObjID builds the object ID (file-name-like, ".ics" suffixed) used to
|
||||
// address a fetched VEVENT within its subscription calendar, derived from
|
||||
// its UID so it stays stable across fetches of the same feed.
|
||||
func icsObjID(uid string) string {
|
||||
sum := sha1.Sum([]byte(uid))
|
||||
return hex.EncodeToString(sum[:]) + ".ics"
|
||||
}
|
||||
|
||||
// listICSSubscriptionCalendarObjects fetches sub's remote calendar (via
|
||||
// b.icsCache) and returns one caldav.CalendarObject per VEVENT.
|
||||
// icsSubscriptionCalendarObjects fetches sub's remote calendar (via
|
||||
// b.icsCache) and returns one caldav.CalendarObject per VEVENT. The
|
||||
// object path is derived from icssub.EventID(ev) so the same event keeps
|
||||
// the same path across fetches, even if its position in the document
|
||||
// changes.
|
||||
func (b *Backend) listICSSubscriptionCalendarObjects(localName string, sub db.ICSSubscription) ([]caldav.CalendarObject, error) {
|
||||
cal, err := b.icsCache.Get(sub.URL)
|
||||
if err != nil {
|
||||
@@ -58,8 +53,8 @@ func (b *Backend) listICSSubscriptionCalendarObjects(localName string, sub db.IC
|
||||
}
|
||||
|
||||
var objs []caldav.CalendarObject
|
||||
for i, ev := range cal.Events() {
|
||||
obj, err := b.encodeICSObject(localName, ev, fmt.Sprintf("event-%d", i))
|
||||
for _, ev := range cal.Events() {
|
||||
obj, err := b.encodeICSObject(localName, ev)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -75,24 +70,25 @@ func (b *Backend) icsSubscriptionCalendarObject(localName, objID string, sub db.
|
||||
if err != nil {
|
||||
return nil, webdav.NewHTTPError(http.StatusNotFound, fmt.Errorf("fetching ics subscription: %w", err))
|
||||
}
|
||||
for i, ev := range cal.Events() {
|
||||
uid := icsObjectUID(ev, fmt.Sprintf("event-%d", i))
|
||||
if icsObjID(uid) != objID {
|
||||
for _, ev := range cal.Events() {
|
||||
if icssub.EventID(ev) != objID {
|
||||
continue
|
||||
}
|
||||
return b.encodeICSObject(localName, ev, fmt.Sprintf("event-%d", i))
|
||||
return b.encodeICSObject(localName, ev)
|
||||
}
|
||||
return nil, webdav.NewHTTPError(http.StatusNotFound, fmt.Errorf("ics subscription event not found"))
|
||||
}
|
||||
|
||||
// encodeICSObject wraps a single fetched VEVENT ev into its own
|
||||
// caldav.CalendarObject, encoding it as a standalone one-event calendar
|
||||
// the same way every other calendar object in this backend is
|
||||
// represented. fallbackUID is used to derive the object ID/UID if ev has
|
||||
// no UID property of its own.
|
||||
func (b *Backend) encodeICSObject(localName string, ev ical.Event, fallbackUID string) (*caldav.CalendarObject, error) {
|
||||
uid := icsObjectUID(ev, fallbackUID)
|
||||
objID := icsObjID(uid)
|
||||
// the same way every other calendar object in this backend is represented.
|
||||
func (b *Backend) encodeICSObject(localName string, ev ical.Event) (*caldav.CalendarObject, error) {
|
||||
objID := icssub.EventID(ev)
|
||||
if objID == "" {
|
||||
// Not addressable (no DTSTART) — skip.
|
||||
return nil, fmt.Errorf("event has no DTSTART; not addressable")
|
||||
}
|
||||
uid := icsObjectUID(ev, objID)
|
||||
|
||||
event := ical.NewEvent()
|
||||
event.Props = ev.Props
|
||||
|
||||
Reference in New Issue
Block a user