diff --git a/gcalendar/calendar_tools.py b/gcalendar/calendar_tools.py index 49112dcf..f00a8631 100644 --- a/gcalendar/calendar_tools.py +++ b/gcalendar/calendar_tools.py @@ -77,7 +77,6 @@ def _correct_time_format_for_api( logger.info(f"{param_name} '{time_str}' doesn't need formatting, using as is.") return time_str - @server.tool() @require_google_service("calendar", "calendar_read") @handle_http_errors("list_calendars") @@ -112,6 +111,7 @@ async def list_calendars(service, user_google_email: str) -> str: return text_output + @server.tool() @require_google_service("calendar", "calendar_read") @handle_http_errors("get_events") @@ -182,15 +182,7 @@ async def get_events( event_details_list = [] for item in items: - summary = item.get("summary", "No Title") - start_time = item["start"].get("dateTime", item["start"].get("date")) - end_time = item["end"].get("dateTime", item["end"].get("date")) - link = item.get("htmlLink", "No Link") - event_id = item.get("id", "No ID") - # Include the start/end date, and event ID in the output so users can copy it for modify/delete operations - event_details_list.append( - f'- "{summary}" (Starts: {start_time}, Ends: {end_time}) ID: {event_id} | Link: {link}' - ) + event_details_list.append(_format_event_details(item, user_google_email)) text_output = ( f"Successfully retrieved {len(items)} events from calendar '{calendar_id}' for {user_google_email}:\n" @@ -531,6 +523,11 @@ async def get_event( location = event.get("location", "No Location") attendees = event.get("attendees", []) attendee_emails = ", ".join([a.get("email", "") for a in attendees]) if attendees else "None" + color = event.get("colorId", "No Color") + + response_status = _is_user_attending_event(attendees, event, user_google_email) + attending_str = _format_attendance_status(response_status) + event_details = ( f'Event Details:\n' f'- Title: {summary}\n' @@ -539,8 +536,80 @@ async def get_event( f'- Description: {description}\n' f'- Location: {location}\n' f'- Attendees: {attendee_emails}\n' + f'- Attending myself: {attending_str}\n' f'- Event ID: {event_id}\n' - f'- Link: {link}' + f'- Link: {link}\n' + f'- Color: {color}' ) logger.info(f"[get_event] Successfully retrieved event {event_id} for {user_google_email}.") return event_details + + +def _is_user_attending_event(attendees, event, user_google_email): + """ + Determines if the user is attending the event (not declined). + Args: + attendees (list): List of attendee dicts. + event (dict): The event object. + user_google_email (str): The user's Google email address. + Returns: + bool: True if attending, False otherwise. + """ + """ + Returns one of: 'accepted', 'tentative', 'needsAction', 'declined', or None if not found. + """ + for attendee in attendees: + email = attendee.get("email", "") + response_status = attendee.get("responseStatus", "needsAction") + if email.lower() == user_google_email.lower(): + return response_status + # If no attendees and creator is myself, treat as accepted + if not attendees: + creator = event.get("creator", {}).get("email", "") + if creator.lower() == user_google_email.lower(): + return "accepted" + return None + +def _format_event_details(item: Dict[str, Any], user_google_email: str) -> str: + """ + Formats event details into a standardized string format. + + Args: + item (Dict[str, Any]): Event item from Google Calendar API. + + Returns: + str: Formatted event details string. + """ + summary = item.get("summary", "No Title") + start_time = item["start"].get("dateTime", item["start"].get("date")) + end_time = item["end"].get("dateTime", item["end"].get("date")) + link = item.get("htmlLink", "No Link") + event_id = item.get("id", "No ID") + attending = _format_attendance_status( + _is_user_attending_event(item.get("attendees", []), item, user_google_email) + ) + color = item.get("colorId", "No Color") + + return f'- "{summary}" (Starts: {start_time}, Ends: {end_time}) ID: {event_id} | Link: {link} | Attending myself: {attending} | Color: {color}' + +def _format_attendance_status(response_status: Optional[str]) -> str: + """ + Converts a Google Calendar response status to a human-readable attendance string. + + Args: + response_status (Optional[str]): The response status from Google Calendar API. + Can be 'accepted', 'tentative', 'needsAction', 'declined', or None. + + Returns: + str: Human-readable attendance status. + """ + if response_status == "accepted": + return "Yes" + elif response_status == "tentative": + return "Tentative" + elif response_status == "needsAction": + return "No response yet" + elif response_status == "declined": + return "No" + else: + return "Unknown"