Skip to content

Commit 55fbb7d

Browse files
committed
refac
1 parent 5a545db commit 55fbb7d

5 files changed

Lines changed: 495 additions & 9 deletions

File tree

gcalendar/calendar_tools.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ async def _create_event_impl(
635635
use_default_reminders: bool = True,
636636
transparency: Optional[str] = None,
637637
visibility: Optional[str] = None,
638+
recurrence: Optional[List[str]] = None,
638639
guests_can_modify: Optional[bool] = None,
639640
guests_can_invite_others: Optional[bool] = None,
640641
guests_can_see_other_guests: Optional[bool] = None,
@@ -657,6 +658,8 @@ async def _create_event_impl(
657658
),
658659
"end": ({"date": end_time} if "T" not in end_time else {"dateTime": end_time}),
659660
}
661+
if recurrence:
662+
event_body["recurrence"] = recurrence
660663
if location:
661664
event_body["location"] = location
662665
if description:
@@ -883,6 +886,7 @@ async def _modify_event_impl(
883886
transparency: Optional[str] = None,
884887
visibility: Optional[str] = None,
885888
color_id: Optional[str] = None,
889+
recurrence: Optional[List[str]] = None,
886890
guests_can_modify: Optional[bool] = None,
887891
guests_can_invite_others: Optional[bool] = None,
888892
guests_can_see_other_guests: Optional[bool] = None,
@@ -920,6 +924,8 @@ async def _modify_event_impl(
920924

921925
if color_id is not None:
922926
event_body["colorId"] = color_id
927+
if recurrence is not None:
928+
event_body["recurrence"] = recurrence
923929

924930
# Handle reminders
925931
if reminders is not None or use_default_reminders is not None:
@@ -1028,6 +1034,7 @@ async def _modify_event_impl(
10281034
# Use the already-normalized attendee objects (if provided); otherwise preserve existing
10291035
"attendees": event_body.get("attendees"),
10301036
"colorId": event_body.get("colorId"),
1037+
"recurrence": recurrence,
10311038
},
10321039
)
10331040

@@ -1178,6 +1185,7 @@ async def manage_event(
11781185
transparency: Optional[str] = None,
11791186
visibility: Optional[str] = None,
11801187
color_id: Optional[str] = None,
1188+
recurrence: Optional[StringList] = None,
11811189
guests_can_modify: Optional[bool] = None,
11821190
guests_can_invite_others: Optional[bool] = None,
11831191
guests_can_see_other_guests: Optional[bool] = None,
@@ -1204,6 +1212,7 @@ async def manage_event(
12041212
transparency (Optional[str]): "opaque" (busy) or "transparent" (free).
12051213
visibility (Optional[str]): "default", "public", "private", or "confidential".
12061214
color_id (Optional[str]): Event color ID (1-11, update only).
1215+
recurrence (Optional[List[str]]): RFC5545 recurrence rules for a recurring event, e.g. ["RRULE:FREQ=WEEKLY;COUNT=10"].
12071216
guests_can_modify (Optional[bool]): Whether attendees can modify.
12081217
guests_can_invite_others (Optional[bool]): Whether attendees can invite others.
12091218
guests_can_see_other_guests (Optional[bool]): Whether attendees can see other guests.
@@ -1239,6 +1248,7 @@ async def manage_event(
12391248
guests_can_modify=guests_can_modify,
12401249
guests_can_invite_others=guests_can_invite_others,
12411250
guests_can_see_other_guests=guests_can_see_other_guests,
1251+
recurrence=recurrence,
12421252
)
12431253
elif action_lower == "update":
12441254
if not event_id:
@@ -1261,6 +1271,7 @@ async def manage_event(
12611271
transparency=transparency,
12621272
visibility=visibility,
12631273
color_id=color_id,
1274+
recurrence=recurrence,
12641275
guests_can_modify=guests_can_modify,
12651276
guests_can_invite_others=guests_can_invite_others,
12661277
guests_can_see_other_guests=guests_can_see_other_guests,
@@ -1325,6 +1336,7 @@ async def _create_ooo_event_impl(
13251336
summary: Optional[str] = None,
13261337
auto_decline_mode: Optional[str] = None,
13271338
decline_message: Optional[str] = None,
1339+
recurrence: Optional[List[str]] = None,
13281340
timezone: Optional[str] = None,
13291341
) -> str:
13301342
"""Internal implementation for creating an Out of Office calendar event."""
@@ -1348,6 +1360,8 @@ async def _create_ooo_event_impl(
13481360
},
13491361
"transparency": "opaque",
13501362
}
1363+
if recurrence:
1364+
event_body["recurrence"] = recurrence
13511365

13521366
created_event = await asyncio.to_thread(
13531367
lambda: (
@@ -1470,6 +1484,7 @@ async def _update_ooo_event_impl(
14701484
summary: Optional[str] = None,
14711485
auto_decline_mode: Optional[str] = None,
14721486
decline_message: Optional[str] = None,
1487+
recurrence: Optional[List[str]] = None,
14731488
timezone: Optional[str] = None,
14741489
) -> str:
14751490
"""Internal implementation for updating an Out of Office calendar event."""
@@ -1497,6 +1512,8 @@ async def _update_ooo_event_impl(
14971512
)
14981513
if end_time is not None:
14991514
patch_body["end"] = _ooo_time_entry(end_time, is_end=True, timezone=timezone)
1515+
if recurrence is not None:
1516+
patch_body["recurrence"] = recurrence
15001517

15011518
if auto_decline_mode is not None or decline_message is not None:
15021519
existing_ooo_props = existing_event.get("outOfOfficeProperties", {})
@@ -1601,6 +1618,7 @@ async def manage_out_of_office(
16011618
summary: Optional[str] = None,
16021619
auto_decline_mode: Optional[str] = None,
16031620
decline_message: Optional[str] = None,
1621+
recurrence: Optional[StringList] = None,
16041622
timezone: Optional[str] = None,
16051623
time_min: Optional[str] = None,
16061624
time_max: Optional[str] = None,
@@ -1620,12 +1638,13 @@ async def manage_out_of_office(
16201638
summary (Optional[str]): Display text on the calendar. Defaults to "Out of Office".
16211639
auto_decline_mode (Optional[str]): How to handle conflicting invitations. One of: "declineAllConflictingInvitations" (default), "declineOnlyNewConflictingInvitations", "declineNone".
16221640
decline_message (Optional[str]): Message included when auto-declining invitations.
1641+
recurrence (Optional[List[str]]): RFC5545 recurrence rules for a recurring Out of Office series, e.g. ["RRULE:FREQ=WEEKLY;COUNT=10"].
16231642
timezone (Optional[str]): Timezone for the event (e.g., "America/New_York", "Europe/London"). Required when using date-only values or dateTime values without an explicit UTC offset.
1624-
time_min (Optional[str]): For "list" action: start of time range. Defaults to current time.
1643+
time_min (Optional[str]): For "list" action: start of time range. Defaults to current time. Recurring series are expanded into individual instances in the requested range.
16251644
time_max (Optional[str]): For "list" action: end of time range.
16261645
max_results (int): For "list" action: maximum events to return. Defaults to 10.
16271646
event_id (Optional[str]): Event ID. Required for "update" and "delete" actions.
1628-
calendar_id (str): Calendar ID. Defaults to 'primary'. OOO events are typically on the primary calendar.
1647+
calendar_id (str): Calendar ID. Defaults to 'primary'. Out of Office status events live on primary calendars, so use 'primary' or a user's primary calendar ID/email rather than a secondary calendar ID.
16291648
16301649
Returns:
16311650
str: Confirmation message with event details, or a formatted list of OOO events.
@@ -1643,6 +1662,7 @@ async def manage_out_of_office(
16431662
summary=summary,
16441663
auto_decline_mode=auto_decline_mode,
16451664
decline_message=decline_message,
1665+
recurrence=recurrence,
16461666
timezone=timezone,
16471667
)
16481668
elif action_lower == "list":
@@ -1668,6 +1688,7 @@ async def manage_out_of_office(
16681688
summary=summary,
16691689
auto_decline_mode=auto_decline_mode,
16701690
decline_message=decline_message,
1691+
recurrence=recurrence,
16711692
timezone=timezone,
16721693
)
16731694
elif action_lower == "delete":
@@ -1741,6 +1762,7 @@ async def _create_focus_time_event_impl(
17411762
auto_decline_mode: Optional[str] = None,
17421763
decline_message: Optional[str] = None,
17431764
chat_status: Optional[str] = None,
1765+
recurrence: Optional[List[str]] = None,
17441766
timezone: Optional[str] = None,
17451767
) -> str:
17461768
"""Internal implementation for creating a Focus Time calendar event."""
@@ -1752,7 +1774,9 @@ async def _create_focus_time_event_impl(
17521774
effective_decline_mode = _validate_auto_decline_mode(
17531775
auto_decline_mode, "create_focus_time_event"
17541776
)
1755-
validated_chat_status = _validate_chat_status(chat_status, "create_focus_time_event")
1777+
validated_chat_status = _validate_chat_status(
1778+
chat_status or "doNotDisturb", "create_focus_time_event"
1779+
)
17561780

17571781
focus_time_props: Dict[str, str] = {
17581782
"autoDeclineMode": effective_decline_mode,
@@ -1769,6 +1793,8 @@ async def _create_focus_time_event_impl(
17691793
"focusTimeProperties": focus_time_props,
17701794
"transparency": "opaque",
17711795
}
1796+
if recurrence:
1797+
event_body["recurrence"] = recurrence
17721798

17731799
created_event = await asyncio.to_thread(
17741800
lambda: (
@@ -1896,6 +1922,7 @@ async def _update_focus_time_event_impl(
18961922
auto_decline_mode: Optional[str] = None,
18971923
decline_message: Optional[str] = None,
18981924
chat_status: Optional[str] = None,
1925+
recurrence: Optional[List[str]] = None,
18991926
timezone: Optional[str] = None,
19001927
) -> str:
19011928
"""Internal implementation for updating a Focus Time calendar event."""
@@ -1923,6 +1950,8 @@ async def _update_focus_time_event_impl(
19231950
)
19241951
if end_time is not None:
19251952
patch_body["end"] = _focus_time_time_entry(end_time, is_end=True, timezone=timezone)
1953+
if recurrence is not None:
1954+
patch_body["recurrence"] = recurrence
19261955

19271956
if auto_decline_mode is not None or decline_message is not None or chat_status is not None:
19281957
existing_ft_props = existing_event.get("focusTimeProperties", {})
@@ -2034,6 +2063,7 @@ async def manage_focus_time(
20342063
auto_decline_mode: Optional[str] = None,
20352064
decline_message: Optional[str] = None,
20362065
chat_status: Optional[str] = None,
2066+
recurrence: Optional[StringList] = None,
20372067
timezone: Optional[str] = None,
20382068
time_min: Optional[str] = None,
20392069
time_max: Optional[str] = None,
@@ -2043,8 +2073,8 @@ async def manage_focus_time(
20432073
) -> str:
20442074
"""
20452075
Manages Focus Time events on Google Calendar. These special events auto-decline
2046-
meeting invitations and set the user's chat status to Do Not Disturb, helping
2047-
protect blocks of uninterrupted work time.
2076+
meeting invitations and, by default, set the user's chat status to Do Not
2077+
Disturb, helping protect blocks of uninterrupted work time.
20482078
20492079
Args:
20502080
user_google_email (str): The user's Google email address. Required.
@@ -2054,13 +2084,14 @@ async def manage_focus_time(
20542084
summary (Optional[str]): Display text on the calendar. Defaults to "Focus Time".
20552085
auto_decline_mode (Optional[str]): How to handle conflicting invitations. One of: "declineAllConflictingInvitations" (default), "declineOnlyNewConflictingInvitations", "declineNone".
20562086
decline_message (Optional[str]): Message included when auto-declining invitations.
2057-
chat_status (Optional[str]): Google Chat status during the focus time. Currently supports: "doNotDisturb".
2087+
chat_status (Optional[str]): Google Chat status during the focus time. Supports "doNotDisturb" (default) and "available".
2088+
recurrence (Optional[List[str]]): RFC5545 recurrence rules for a recurring Focus Time series, e.g. ["RRULE:FREQ=WEEKLY;COUNT=10"].
20582089
timezone (Optional[str]): Timezone for the event (e.g., "America/New_York", "Europe/London"). Required when using date-only values or dateTime values without an explicit UTC offset.
2059-
time_min (Optional[str]): For "list" action: start of time range. Defaults to current time.
2090+
time_min (Optional[str]): For "list" action: start of time range. Defaults to current time. Recurring series are expanded into individual instances in the requested range.
20602091
time_max (Optional[str]): For "list" action: end of time range.
20612092
max_results (int): For "list" action: maximum events to return. Defaults to 10.
20622093
event_id (Optional[str]): Event ID. Required for "update" and "delete" actions.
2063-
calendar_id (str): Calendar ID. Defaults to 'primary'. Focus Time events are typically on the primary calendar.
2094+
calendar_id (str): Calendar ID. Defaults to 'primary'. Focus Time status events live on primary calendars, so use 'primary' or a user's primary calendar ID/email rather than a secondary calendar ID.
20642095
20652096
Returns:
20662097
str: Confirmation message with event details, or a formatted list of Focus Time events.
@@ -2079,6 +2110,7 @@ async def manage_focus_time(
20792110
auto_decline_mode=auto_decline_mode,
20802111
decline_message=decline_message,
20812112
chat_status=chat_status,
2113+
recurrence=recurrence,
20822114
timezone=timezone,
20832115
)
20842116
elif action_lower == "list":
@@ -2105,6 +2137,7 @@ async def manage_focus_time(
21052137
auto_decline_mode=auto_decline_mode,
21062138
decline_message=decline_message,
21072139
chat_status=chat_status,
2140+
recurrence=recurrence,
21082141
timezone=timezone,
21092142
)
21102143
elif action_lower == "delete":

0 commit comments

Comments
 (0)