from __future__ import annotations import urllib.parse from collections.abc import Mapping, Sequence from typing import Any import requests from dify_plugin.entities.trigger import Variables from dify_plugin.errors.trigger import EventIgnoreError _CAL_BASE = "https://www.googleapis.com/calendar/v3" def collect_events(payload: Mapping[str, Any], key: str) -> list[dict[str, Any]]: raw_items = payload.get(key) if not isinstance(raw_items, Sequence): return [] events: list[dict[str, Any]] = [] for item in raw_items: if isinstance(item, Mapping): events.append(dict(item)) return events def resolve_calendar_id(runtime: Any, payload: Mapping[str, Any], parameters: Mapping[str, Any]) -> str: subscription_params: Mapping[str, Any] = {} if getattr(runtime, "subscription", None): subscription_params = runtime.subscription.parameters or {} calendar_id = ( payload.get("calendarId") or parameters.get("calendar_id") or subscription_params.get("calendar_id") or "primary" ) return str(calendar_id) def get_access_token(runtime: Any) -> str: credentials: Mapping[str, Any] = {} if getattr(runtime, "credentials", None): credentials = runtime.credentials or {} token = credentials.get("access_token") if not token: raise ValueError("Missing Google Calendar OAuth access token in runtime credentials") return str(token) def enrich_events( runtime: Any, *, calendar_id: str, events: list[dict[str, Any]], include_deleted: bool, ) -> list[dict[str, Any]]: if not events: return events access_token = get_access_token(runtime) headers = {"Authorization": f"Bearer {access_token}"} encoded_calendar = urllib.parse.quote(calendar_id, safe="@._-") enriched: list[dict[str, Any]] = [] for event in events: event_id = str(event.get("id") or "").strip() if not event_id: continue encoded_event = urllib.parse.quote(event_id, safe="@._-") params = {"showDeleted": "true"} if include_deleted else None try: resp = requests.get( f"{_CAL_BASE}/calendars/{encoded_calendar}/events/{encoded_event}", headers=headers, params=params, timeout=10, ) except requests.RequestException: enriched.append(event) continue if resp.status_code == 200: try: enriched.append(resp.json() or {}) except Exception: enriched.append(event) elif resp.status_code == 404 and include_deleted: enriched.append(event) else: enriched.append(event) return enriched or events def build_variables(payload: Mapping[str, Any], calendar_id: str, events: list[dict[str, Any]]) -> Variables: if not events: raise EventIgnoreError() variables = { "calendar_id": calendar_id, "resource_state": payload.get("resourceState"), "resource_id": payload.get("resourceId"), "channel_id": payload.get("channelId"), "next_sync_token": payload.get("nextSyncToken"), "events": events, } include_cancelled = payload.get("includeCancelled") if include_cancelled: variables["include_cancelled"] = include_cancelled return Variables(variables=variables) def ensure_events_or_raise(events: list[dict[str, Any]]) -> None: if not events: raise EventIgnoreError() def should_enrich_details(runtime: Any, parameters: Mapping[str, Any]) -> bool: if "enrich_event_details" in parameters: return bool(parameters.get("enrich_event_details")) if getattr(runtime, "subscription", None): subscription_params = runtime.subscription.parameters or {} if "enrich_event_details" in subscription_params: return bool(subscription_params.get("enrich_event_details")) return True