Add external calendar profile contract

This commit is contained in:
2026-08-02 05:59:06 +02:00
parent d6255f9f8f
commit ca35aad286
2 changed files with 71 additions and 2 deletions
+4 -2
View File
@@ -208,7 +208,8 @@ Other stable runtime capabilities currently include:
- `identity.directory` and `identity.search`
- `organizations.directory`
- `idm.directory`
- `calendar.outbox` and `calendar.scheduling`
- `calendar.outbox`, `calendar.scheduling`, `calendar.invitations`, and
`calendar.externalProfiles`
- `poll.scheduling`
- `notifications.dispatch`
- `workflow.definitionContributions` and `workflow.runtimeWorker`
@@ -286,7 +287,8 @@ Current named interfaces, generated from the source manifests by the workspace
contract checks, are:
- `addresses.contact_writer`, `addresses.lookup`, `addresses.recipient_source`
- `calendar.outbox`, `calendar.scheduling`
- `calendar.external_profiles`, `calendar.invitations`, `calendar.outbox`,
`calendar.scheduling`
- `campaigns.access`, `campaigns.delivery_tasks`,
`campaigns.mail_policy_context`, `campaigns.policy_context`,
`campaigns.retention`
+67
View File
@@ -9,6 +9,7 @@ from typing import Protocol, runtime_checkable
CAPABILITY_CALENDAR_SCHEDULING = "calendar.scheduling"
CAPABILITY_CALENDAR_OUTBOX = "calendar.outbox"
CAPABILITY_CALENDAR_INVITATIONS = "calendar.invitations"
CAPABILITY_CALENDAR_EXTERNAL_PROFILES = "calendar.externalProfiles"
CALENDAR_AVAILABILITY_READ_SCOPE = "calendar:availability:read"
CALENDAR_EVENT_WRITE_SCOPE = "calendar:event:write"
@@ -90,6 +91,38 @@ class CalendarInvitationRef:
degraded_reasons: tuple[str, ...] = ()
@dataclass(frozen=True, slots=True)
class CalendarExternalProfileRequest:
"""Connector-neutral request for a Calendar-owned external profile."""
profile_kind: str
calendar_id: str
endpoint_url: str
display_name: str | None = None
auth_type: str = "none"
username: str | None = None
credential_ref: str | None = None
sync_enabled: bool = True
sync_interval_seconds: int = 900
sync_direction: str = "two_way"
conflict_policy: str = "etag"
connector_profile_ref: str | None = None
identity_mapping_ref: str | None = None
resource_calendar_ref: str | None = None
metadata: Mapping[str, object] = field(default_factory=dict)
@dataclass(frozen=True, slots=True)
class CalendarExternalProfileRef:
source_id: str
calendar_id: str
profile_kind: str
transport_kind: str
connector_profile_ref: str | None = None
identity_mapping_ref: str | None = None
resource_calendar_ref: str | None = None
@runtime_checkable
class CalendarSchedulingProvider(Protocol):
def list_freebusy(
@@ -165,6 +198,25 @@ class CalendarInvitationProvider(Protocol):
) -> CalendarInvitationRef:
...
@runtime_checkable
class CalendarExternalProfileProvider(Protocol):
"""Optional connector route for Calendar-owned groupware adapters."""
def supported_profiles(self) -> Sequence[Mapping[str, object]]:
...
def configure_profile(
self,
session: object,
*,
tenant_id: str,
user_id: str | None,
request: CalendarExternalProfileRequest,
) -> CalendarExternalProfileRef:
...
def calendar_scheduling_provider(registry: object | None) -> CalendarSchedulingProvider | None:
if registry is None or not hasattr(registry, "has_capability"):
return None
@@ -192,3 +244,18 @@ def calendar_invitation_provider(
return None
capability = registry.capability(CAPABILITY_CALENDAR_INVITATIONS)
return capability if isinstance(capability, CalendarInvitationProvider) else None
def calendar_external_profile_provider(
registry: object | None,
) -> CalendarExternalProfileProvider | None:
if registry is None or not hasattr(registry, "has_capability"):
return None
if not registry.has_capability(CAPABILITY_CALENDAR_EXTERNAL_PROFILES):
return None
capability = registry.capability(CAPABILITY_CALENDAR_EXTERNAL_PROFILES)
return (
capability
if isinstance(capability, CalendarExternalProfileProvider)
else None
)