From 7571a34cfeb954420fee01471385bcb641c0a9fd Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 7 Mar 2026 16:49:41 +0000 Subject: [PATCH] fix(contacts): send required other-contact copy mask (#384) (thanks @rbansal42) --- CHANGELOG.md | 1 + internal/cmd/contacts_crud_error_test.go | 10 ++++++++++ internal/cmd/contacts_directory.go | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e4ae5e..f25e7ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Timezone: embed the IANA timezone database so Windows builds can resolve calendar timezones correctly. (#388) — thanks @visionik. - Google API: use transport-level response-header timeouts for API clients while keeping token exchanges bounded, so large downloads are not cut short by `http.Client.Timeout`. (#425) — thanks @laihenyi. - Auth: keep Keep-only service-account fallback isolated to Keep commands so other Google services do not accidentally pick it up. (#414) — thanks @jgwesterlund. +- Contacts: send the required `copyMask` when deleting "other contacts", avoiding People API 400 errors. (#384) — thanks @rbansal42. - Gmail: add a fetch delay in `watch serve` so History API reads don't race message indexing. (#397) — thanks @salmonumbrella. - Gmail: allow Workspace-managed send-as aliases with empty verification status in `send` and `drafts create`. (#407) — thanks @salmonumbrella. - Gmail: preserve the selected `--client` during `watch serve` push handling instead of falling back to the default client. (#411) — thanks @chrysb. diff --git a/internal/cmd/contacts_crud_error_test.go b/internal/cmd/contacts_crud_error_test.go index 4d17c6f..a2f77a1 100644 --- a/internal/cmd/contacts_crud_error_test.go +++ b/internal/cmd/contacts_crud_error_test.go @@ -120,6 +120,16 @@ func TestContactsOtherDelete_Success_JSON(t *testing.T) { svc, closeSrv := newPeopleService(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch { case strings.Contains(r.URL.Path, "otherContacts/") && strings.Contains(r.URL.Path, ":copyOtherContactToMyContactsGroup") && r.Method == http.MethodPost: + var req struct { + CopyMask string `json:"copyMask"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + t.Fatalf("decode request: %v", err) + } + if req.CopyMask != otherContactCopyMask { + t.Fatalf("expected copyMask %q, got %q", otherContactCopyMask, req.CopyMask) + } + // Mock CopyOtherContactToMyContactsGroup response w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{ diff --git a/internal/cmd/contacts_directory.go b/internal/cmd/contacts_directory.go index 7ad705c..08cb27b 100644 --- a/internal/cmd/contacts_directory.go +++ b/internal/cmd/contacts_directory.go @@ -420,6 +420,8 @@ type ContactsOtherDeleteCmd struct { ResourceName string `arg:"" name:"resourceName" help:"Resource name (otherContacts/...)"` } +const otherContactCopyMask = "names,phoneNumbers,emailAddresses,organizations,biographies,urls,addresses,birthdays,events,relations,userDefined" + func (c *ContactsOtherDeleteCmd) Run(ctx context.Context, flags *RootFlags) error { u := ui.FromContext(ctx) resourceName := strings.TrimSpace(c.ResourceName) @@ -452,7 +454,7 @@ func deleteOtherContact(ctx context.Context, account, resourceName string) error &people.CopyOtherContactToMyContactsGroupRequest{ // CopyMask is required by the People API; omitting it causes a 400 "copyMask is required" error. // See: https://developers.google.com/people/api/rest/v1/otherContacts/copyOtherContactToMyContactsGroup - CopyMask: "names,phoneNumbers,emailAddresses,organizations,biographies,urls,addresses,birthdays,events,relations,userDefined", + CopyMask: otherContactCopyMask, }, ).Do() if err != nil {