List Google calendars and choose the one to push to (Feature 16)
CI / ci (push) Successful in 3m49s
CI / ci (pull_request) Successful in 3m34s

GET /api/v1/integrations/google/calendars trades the stored refresh token
for an access token, reads every calendarList page and answers
[{id, summary, primary, accessRole}] for writer and owner calendars only.
PUT /api/v1/integrations/google/calendar {calendar_id} validates the id
against that same filtered listing and stores calendar_id and
calendar_name; any other id is 422 unknown_calendar.

Both hold the service's account lock, answer 409 not_connected with
nothing connected, and 502 reconnect_required when Google no longer
accepts the grant, leaving the connection as it is. The gcaltest fake
gains the refresh grant and a pausable calendarList endpoint.

Maestro task 0fe3f1f2-4932-4d10-81dd-74c4f630d215.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 21:15:24 -04:00
co-authored by Claude Opus 5.5
parent f06b57c921
commit 1e3e42e0b1
14 changed files with 1007 additions and 44 deletions
+3 -1
View File
@@ -73,6 +73,7 @@ func newHarness(t *testing.T) *harness {
SecretKey: []byte("server-secret-key"),
Endpoint: google.Endpoint(),
RevokeURL: google.RevokeURL(),
CalendarAPI: google.CalendarAPI(),
})
if err != nil {
t.Fatal(err)
@@ -535,7 +536,7 @@ func TestNewServiceRequiresConfig(t *testing.T) {
pub, _ := url.Parse(publicURL)
valid := gcal.Config{
ClientID: "id", ClientSecret: "secret", PublicURL: pub, SecretKey: []byte("k"),
Endpoint: gcal.GoogleEndpoint, RevokeURL: gcal.GoogleRevokeURL,
Endpoint: gcal.GoogleEndpoint, RevokeURL: gcal.GoogleRevokeURL, CalendarAPI: gcal.GoogleCalendarAPI,
}
if _, err := gcal.NewService(h.st, h.box, valid); err != nil {
t.Fatalf("valid config: %v", err)
@@ -547,6 +548,7 @@ func TestNewServiceRequiresConfig(t *testing.T) {
"secret key": func(c *gcal.Config) { c.SecretKey = nil },
"token URL": func(c *gcal.Config) { c.Endpoint.TokenURL = "" },
"revoke URL": func(c *gcal.Config) { c.RevokeURL = "" },
"Calendar API": func(c *gcal.Config) { c.CalendarAPI = "" },
} {
cfg := valid
edit(&cfg)