package calendar import ( "fmt" "strconv" "strings" "time" ) // ReminderUIDPrefix namespaces every event maven publishes. Two reasons it is a // fixed prefix and not a random UUID: the render is idempotent (the same // reminder always lands on the same UID, so re-rendering overwrites instead of // duplicating), and everything maven owns in the target collection is // identifiable at a glance — she never touches a file she did not create. const ReminderUIDPrefix = "maven-reminder-" // DefaultReminderDuration — how long a rendered reminder occupies. A reminder // is an instant, a calendar entry is a span, so one has to be invented; 30 // minutes reads as a block in a calendar app without swallowing the afternoon. const DefaultReminderDuration = 30 * time.Minute // ReminderEvent maps a reminder to the event that represents it. id and fire // come from the store; payload is the RU text as the owner said it, rendered // verbatim as the summary — the calendar is a view of sqlite, not a place to // rephrase. func ReminderEvent(id int64, fire time.Time, payload string, dur time.Duration) Event { if dur <= 0 { dur = DefaultReminderDuration } summary := strings.TrimSpace(payload) if summary == "" { summary = "напоминание" } return Event{ UID: fmt.Sprintf("%s%d", ReminderUIDPrefix, id), Summary: summary, Start: fire, End: fire.Add(dur), } } // ReminderPath is the collection-relative filename for a rendered reminder. // One event per resource, per the CalDAV convention. func ReminderPath(id int64) string { return fmt.Sprintf("%s%d.ics", ReminderUIDPrefix, id) } // ReminderIDFromPath reads back what ReminderPath wrote, given an href out of a // PROPFIND. It reports false for anything that is not a resource maven // published, which is what keeps a reconciliation pass from touching a file it // did not create. func ReminderIDFromPath(href string) (int64, bool) { name := href if i := strings.LastIndex(name, "/"); i >= 0 { name = name[i+1:] } if !strings.HasPrefix(name, ReminderUIDPrefix) || !strings.HasSuffix(name, ".ics") { return 0, false } digits := name[len(ReminderUIDPrefix) : len(name)-len(".ics")] if digits == "" { return 0, false } id, err := strconv.ParseInt(digits, 10, 64) if err != nil || id <= 0 { return 0, false } return id, true }