Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

calendar.updateEvent: `attendees` replaces the guest list, so "add a guest" silently removes the others

Aperta
#433 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
58/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Tranquilla
Stack tecnologico
typescript
Ambito
api, backend

Direzione di ricerca

Inizia in CalendarService.ts, in updateEvent, e ispeziona la definizione di UpdateEventInput e lo schema dello strumento in index.ts. Esegui la suite completa, comprese le asserzioni sull’unione dei partecipanti, e verifica che l’aggiunta di invitati preservi gli oggetti dei partecipanti esistenti, che la rimozione funzioni, che un elenco vuoto elimini gli invitati e che gli aggiornamenti senza campi dei partecipanti evitino la lettura aggiuntiva.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Summary

calendar.updateEvent treats attendees as a full replacement of the guest list. So the most common phrasing a user gives an agent — "add Ana to that meeting" — silently removes everyone else who was already invited.

This is not the events.update vs events.patch bug (that one is fixed; updateEvent correctly uses patch today). patch merges at the field level, but attendees is a single field holding an array, and Google replaces the array wholesale. So a partial body still wipes the other guests, and the API returns 200 with the stripped guest list.

Reproduction
  1. Create an event with attendees [email protected] and [email protected].
  2. calendar.updateEvent({ eventId, attendees: ["[email protected]"] }).
  3. The event now has exactly one attendee, [email protected]. a@ and b@ were removed, and they receive cancellation notices.
Proposal

Make attendees mean add, which is what a caller asking to add a guest means, and add an explicit removeAttendees for the opposite intent — a merge alone can never remove anybody, so the removal case needs its own door.

One deliberate exception preserves existing behaviour: an empty attendees array still writes straight through as "clear the guest list". Merging there would make the one intent that cannot be expressed any other way impossible, and it keeps the current semantics (and its test) intact.

Patch

CalendarService.ts, in updateEvent, replacing:

if (attendees !== undefined)
  requestBody.attendees = attendees.map((email) => ({ email }));

with:

// Attendees need read-modify-write even under patch: Google replaces the
// whole array rather than merging into it, so "add one guest" has to
// resend everyone.
if (attendees?.length === 0 && !removeAttendees?.length) {
  requestBody.attendees = [];
} else if (attendees?.length || removeAttendees?.length) {
  const current = await calendar.events.get({
    calendarId: finalCalendarId,
    eventId,
  });
  const dropped = new Set((removeAttendees ?? []).map((e) => e.toLowerCase()));
  const merged = new Map<string, calendar_v3.Schema$EventAttendee>();
  for (const a of current.data.attendees ?? []) {
    const email = a.email?.toLowerCase();
    if (!email || dropped.has(email)) continue;
    merged.set(email, a);
  }
  for (const email of attendees ?? []) {
    const key = email.toLowerCase();
    if (dropped.has(key) || merged.has(key)) continue;
    merged.set(key, { email });
  }
  requestBody.attendees = [...merged.values()];
}

Plus removeAttendees?: string[] on UpdateEventInput, and on the tool schema in index.ts:

attendees: z
  .array(z.string())
  .optional()
  .describe(
    'Email addresses to ADD as attendees. Merged with the guests already on the event, so existing guests are kept. Use removeAttendees to drop someone.',
  ),
removeAttendees: z
  .array(z.string())
  .optional()
  .describe('Email addresses to remove from the event.'),

Notes on the details that matter:

  • Existing attendee objects are re-sent whole, not rebuilt from the email, so each guest keeps their responseStatus. Rebuilding them would reset everyone to needsAction and re-notify the whole list.
  • Comparison is case-insensitive, since Google is.
  • The read is skipped entirely when neither list is given, so the common "just change the title" path still costs one API call.
Verification
  • Full suite green. The merge assertions were watched fail first by reverting the code to replacement semantics, before being trusted.
  • Live against the Google API: adding a second guest to an event that already had one leaves both on the event, with the first guest's response status preserved.
Trade-off, stated plainly

This changes the meaning of attendees on update, so it is a behaviour change, not a pure bug fix. The argument for it is that the current meaning is the one nobody asks for: an agent told "add someone" has no way to comply without first reading the event itself, and every client that does not know to do that silently destroys data. If you would rather keep replacement and add addAttendees/removeAttendees as new fields, the same merge logic applies unchanged.

Happy to open a PR, though the CLA is a gate on our side — the patch above is complete either way.

Lingua principale
TypeScript
Stelle
648
Fork
107
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di gemini-cli-extensions/workspace

Tutte le issue di gemini-cli-extensions/workspace

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.