feat(calendar): en læst Google-kalender, med sit eget endpoint og sin egen sweep
Samme registrering som Gmail, et andet scope og en anden redirect-URI. Google udsteder en refresh-token pr. godkendelse og holder op til hundrede i live pr. konto, hver med sine egne scopes — så en forbundet kalender rører ikke en Gmail, der virker, og at afbryde den ene tager ikke den anden med. Callbacken har sin egen sti. Én callback, der ud fra gemt tilstand afgjorde, hvilket af de to flows der kom tilbage, ville lægge valget af *hvilket token-lager der skrives* bag et opslag — og går det galt, går det galt ved at overskrive en virkende Gmail-forbindelse med kalender-tokens. Begivenhederne caches i et vindue på 90 dage tilbage og et år frem. Et månedsgitter bladrer, og et kald til Google pr. piletast er en kalender, der er langsommere end den kalender, den viser. Vinduet har en kant, og endpointet siger hvor den er: et tomt svar uden forklaring er en kalender, der lydløst påstår, at en dag er fri.
This commit is contained in:
@@ -133,6 +133,12 @@ func New(cfg *config.Config, db *store.DB, log *slog.Logger, web fs.FS) *Server
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(s.requireAuth)
|
||||
r.Get("/oauth/gmail/callback", s.handleGmailCallback)
|
||||
// The calendar comes back on a URI of its own rather than sharing Gmail's.
|
||||
// One callback deciding from stored state which of the two flows had
|
||||
// returned would put the choice of *which token store to write* behind a
|
||||
// lookup — and when that goes wrong it goes wrong by overwriting a working
|
||||
// Gmail connection with calendar tokens.
|
||||
r.Get("/oauth/calendar/callback", s.handleCalendarCallback)
|
||||
})
|
||||
r.Route("/caldav", s.caldavRoutes)
|
||||
|
||||
@@ -316,6 +322,19 @@ func New(cfg *config.Config, db *store.DB, log *slog.Logger, web fs.FS) *Server
|
||||
})
|
||||
})
|
||||
|
||||
// A calendar read from somewhere else, laid under verdande's own dated
|
||||
// tasks. Read-only, so there is no write here to gate: the events are a
|
||||
// copy of somebody else's calendar, and the only thing a person decides
|
||||
// is which of them to look at.
|
||||
r.Route("/calendar", func(r chi.Router) {
|
||||
r.Get("/", s.handleGetCalendar)
|
||||
r.Put("/calendars", s.handleSetCalendars)
|
||||
r.Delete("/", s.handleDisconnectCalendar)
|
||||
r.Post("/authorize", s.handleCalendarAuthorize)
|
||||
r.Post("/sync", s.handleCalendarSyncNow)
|
||||
r.Get("/events", s.handleCalendarEvents)
|
||||
})
|
||||
|
||||
r.Route("/import", func(r chi.Router) {
|
||||
r.Post("/todoist", s.handleImportTodoist)
|
||||
r.Post("/csv", s.handleImportCSV)
|
||||
|
||||
Reference in New Issue
Block a user