Merge pull request #565 from reinlemmens/fix/calendar-meeting-links

Display meeting links in calendar event output
This commit is contained in:
Taylor Wilsdon
2026-03-17 14:32:37 -04:00
committed by GitHub
4 changed files with 62 additions and 4 deletions

View File

@@ -172,6 +172,21 @@ def _preserve_existing_fields(
event_body[field_name] = new_value event_body[field_name] = new_value
def _get_meeting_link(item: Dict[str, Any]) -> str:
"""Extract video meeting link from event conference data or hangoutLink."""
conference_data = item.get("conferenceData")
if conference_data and "entryPoints" in conference_data:
for entry_point in conference_data["entryPoints"]:
if entry_point.get("entryPointType") == "video":
uri = entry_point.get("uri", "")
if uri:
return uri
hangout_link = item.get("hangoutLink", "")
if hangout_link:
return hangout_link
return ""
def _format_attendee_details( def _format_attendee_details(
attendees: List[Dict[str, Any]], indent: str = " " attendees: List[Dict[str, Any]], indent: str = " "
) -> str: ) -> str:
@@ -448,6 +463,8 @@ async def get_events(
) )
attendee_details_str = _format_attendee_details(attendees, indent=" ") attendee_details_str = _format_attendee_details(attendees, indent=" ")
meeting_link = _get_meeting_link(item)
event_details = ( event_details = (
f"Event Details:\n" f"Event Details:\n"
f"- Title: {summary}\n" f"- Title: {summary}\n"
@@ -456,6 +473,10 @@ async def get_events(
f"- Description: {description}\n" f"- Description: {description}\n"
f"- Location: {location}\n" f"- Location: {location}\n"
f"- Color ID: {color_id}\n" f"- Color ID: {color_id}\n"
)
if meeting_link:
event_details += f"- Meeting Link: {meeting_link}\n"
event_details += (
f"- Attendees: {attendee_emails}\n" f"- Attendees: {attendee_emails}\n"
f"- Attendee Details: {attendee_details_str}\n" f"- Attendee Details: {attendee_details_str}\n"
) )
@@ -494,10 +515,16 @@ async def get_events(
) )
attendee_details_str = _format_attendee_details(attendees, indent=" ") attendee_details_str = _format_attendee_details(attendees, indent=" ")
meeting_link = _get_meeting_link(item)
event_detail_parts = ( event_detail_parts = (
f'- "{summary}" (Starts: {start_time}, Ends: {end_time})\n' f'- "{summary}" (Starts: {start_time}, Ends: {end_time})\n'
f" Description: {description}\n" f" Description: {description}\n"
f" Location: {location}\n" f" Location: {location}\n"
)
if meeting_link:
event_detail_parts += f" Meeting Link: {meeting_link}\n"
event_detail_parts += (
f" Attendees: {attendee_emails}\n" f" Attendees: {attendee_emails}\n"
f" Attendee Details: {attendee_details_str}\n" f" Attendee Details: {attendee_details_str}\n"
) )
@@ -513,9 +540,12 @@ async def get_events(
event_details_list.append(event_detail_parts) event_details_list.append(event_detail_parts)
else: else:
# Basic output format # Basic output format
event_details_list.append( meeting_link = _get_meeting_link(item)
f'- "{summary}" (Starts: {start_time}, Ends: {end_time}) ID: {item_event_id} | Link: {link}' basic_line = f'- "{summary}" (Starts: {start_time}, Ends: {end_time})'
) if meeting_link:
basic_line += f" Meeting: {meeting_link}"
basic_line += f" ID: {item_event_id} | Link: {link}"
event_details_list.append(basic_line)
if event_id: if event_id:
# Single event basic output # Single event basic output

View File

@@ -1463,6 +1463,7 @@ async def update_paragraph_style(
indent_end: float = None, indent_end: float = None,
space_above: float = None, space_above: float = None,
space_below: float = None, space_below: float = None,
named_style_type: str = None,
list_type: str = None, list_type: str = None,
list_nesting_level: int = None, list_nesting_level: int = None,
) -> str: ) -> str:
@@ -1488,6 +1489,8 @@ async def update_paragraph_style(
indent_end: Right/end indent in points indent_end: Right/end indent in points
space_above: Space above paragraph in points (e.g., 12 for one line) space_above: Space above paragraph in points (e.g., 12 for one line)
space_below: Space below paragraph in points space_below: Space below paragraph in points
named_style_type: Direct named style type - 'NORMAL_TEXT', 'TITLE', 'SUBTITLE',
'HEADING_1' through 'HEADING_6'. Mutually exclusive with heading_level.
list_type: Create a list from existing paragraphs ('UNORDERED' for bullets, 'ORDERED' for numbers) list_type: Create a list from existing paragraphs ('UNORDERED' for bullets, 'ORDERED' for numbers)
list_nesting_level: Nesting level for lists (0-8, where 0 is top level, default is 0) list_nesting_level: Nesting level for lists (0-8, where 0 is top level, default is 0)
Use higher levels for nested/indented list items Use higher levels for nested/indented list items
@@ -1546,12 +1549,30 @@ async def update_paragraph_style(
if list_nesting_level < 0 or list_nesting_level > 8: if list_nesting_level < 0 or list_nesting_level > 8:
return "Error: list_nesting_level must be between 0 and 8" return "Error: list_nesting_level must be between 0 and 8"
# Validate named_style_type
if named_style_type is not None and heading_level is not None:
return "Error: heading_level and named_style_type are mutually exclusive; provide only one"
if named_style_type is not None:
valid_styles = [
"NORMAL_TEXT", "TITLE", "SUBTITLE",
"HEADING_1", "HEADING_2", "HEADING_3",
"HEADING_4", "HEADING_5", "HEADING_6",
]
if named_style_type not in valid_styles:
return f"Error: Invalid named_style_type '{named_style_type}'. Must be one of: {', '.join(valid_styles)}"
# Build paragraph style object # Build paragraph style object
paragraph_style = {} paragraph_style = {}
fields = [] fields = []
# Handle named_style_type (direct named style)
if named_style_type is not None:
paragraph_style["namedStyleType"] = named_style_type
fields.append("namedStyleType")
# Handle heading level (named style) # Handle heading level (named style)
if heading_level is not None: elif heading_level is not None:
if heading_level < 0 or heading_level > 6: if heading_level < 0 or heading_level > 6:
return "Error: heading_level must be between 0 (normal text) and 6" return "Error: heading_level must be between 0 (normal text) and 6"
if heading_level == 0: if heading_level == 0:

View File

@@ -475,6 +475,7 @@ class BatchOperationManager:
"indent_end", "indent_end",
"space_above", "space_above",
"space_below", "space_below",
"named_style_type",
], ],
"description": "Apply paragraph-level styling (headings, alignment, spacing, indentation)", "description": "Apply paragraph-level styling (headings, alignment, spacing, indentation)",
}, },

View File

@@ -316,6 +316,12 @@ class ValidationManager:
"At least one paragraph style parameter must be provided (heading_level, alignment, line_spacing, indent_first_line, indent_start, indent_end, space_above, space_below, or named_style_type)", "At least one paragraph style parameter must be provided (heading_level, alignment, line_spacing, indent_first_line, indent_start, indent_end, space_above, space_below, or named_style_type)",
) )
if heading_level is not None and named_style_type is not None:
return (
False,
"heading_level and named_style_type are mutually exclusive; provide only one",
)
if named_style_type is not None: if named_style_type is not None:
valid_styles = [ valid_styles = [
"NORMAL_TEXT", "NORMAL_TEXT",