Skip to content

Bug: update_event silently ignores recurrence_rule, categories, attendees, and reminder_minutes #544

@Qub1

Description

@Qub1

Hey! Found another issue while working with the calendar API. When updating an existing event, several fields are silently ignored (the API returns 200 but the changes don't persist).

Root cause

_merge_ical_properties() in client/calendar.py only handles a subset of fields:

# Currently handled in _merge_ical_properties:
title, description, location, status, priority, privacy, url,
start_datetime, end_datetime, timestamps

These fields are supported by _create_ical_event() but missing from the merge function:

  • recurrence_rule (RRULE)
  • categories
  • attendees
  • reminder_minutes (VALARM)

Interestingly, _merge_ical_todo_properties() does handle categories, so it looks like these just weren't carried over to the event merge.

Reproduction

# Update recurrence rule - returns 200 but RRULE unchanged
update_event(calendar_name="general-1", event_uid="...", recurrence_rule="FREQ=WEEKLY;BYDAY=TU;UNTIL=20260208")

# Update categories - same issue
update_event(calendar_name="general-1", event_uid="...", categories="Work")

Suggested fix

Add the missing fields to _merge_ical_properties(), similar to how they're handled in _create_ical_event():

# In _merge_ical_properties(), after the existing field updates:

# Handle recurrence rule
if "recurrence_rule" in event_data:
    rrule_str = event_data["recurrence_rule"]
    if rrule_str:
        component["RRULE"] = vRecur.from_ical(rrule_str)
    elif "RRULE" in component:
        del component["RRULE"]

# Handle categories
if "categories" in event_data:
    categories_str = event_data["categories"]
    if categories_str:
        component["CATEGORIES"] = categories_str.split(",")
    elif "CATEGORIES" in component:
        del component["CATEGORIES"]

# Handle attendees
if "attendees" in event_data:
    attendees_str = event_data["attendees"]
    # Remove existing attendees
    while "ATTENDEE" in component:
        del component["ATTENDEE"]
    if attendees_str:
        for email in attendees_str.split(","):
            if email.strip():
                component.add("attendee", f"mailto:{email.strip()}")

# Handle reminders
if "reminder_minutes" in event_data:
    # Remove existing alarms
    component.subcomponents = [
        sub for sub in component.subcomponents if sub.name != "VALARM"
    ]
    minutes = event_data["reminder_minutes"]
    if minutes > 0:
        alarm = Alarm()
        alarm.add("action", "DISPLAY")
        alarm.add("description", "Event reminder")
        alarm.add("trigger", dt.timedelta(minutes=-minutes))
        component.add_component(alarm)

(The recurring field from event_data can be ignored in the merge since it's just a flag for the create function.)

Found this while working with Claude on a calendar reorganization project. Happy to submit a PR if that's easier!

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions