feat(scheduling): use central people picker
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response, status
|
||||
@@ -9,11 +8,10 @@ from sqlalchemy.orm import Session
|
||||
from govoplan_core.audit.logging import audit_event
|
||||
from govoplan_core.auth import ApiPrincipal, get_api_principal, has_scope
|
||||
from govoplan_core.core.calendar import CALENDAR_AVAILABILITY_READ_SCOPE, CALENDAR_EVENT_WRITE_SCOPE
|
||||
from govoplan_core.core.people import search_visible_people
|
||||
from govoplan_core.db.session import get_session
|
||||
from govoplan_scheduling.backend.manifest import ADMIN_SCOPE, READ_SCOPE, RESPOND_SCOPE, WRITE_SCOPE
|
||||
from govoplan_scheduling.backend.schemas import (
|
||||
SchedulingAddressLookupCandidate,
|
||||
SchedulingAddressLookupResponse,
|
||||
SchedulingAvailabilityResponse,
|
||||
SchedulingAvailabilityResponseRequest,
|
||||
SchedulingCalendarActionResponse,
|
||||
@@ -24,6 +22,9 @@ from govoplan_scheduling.backend.schemas import (
|
||||
SchedulingNotificationCreateRequest,
|
||||
SchedulingNotificationListResponse,
|
||||
SchedulingNotificationResponse,
|
||||
SchedulingPeopleSearchCandidate,
|
||||
SchedulingPeopleSearchGroup,
|
||||
SchedulingPeopleSearchResponse,
|
||||
SchedulingRequestCreateRequest,
|
||||
SchedulingRequestListResponse,
|
||||
SchedulingRequestResponse,
|
||||
@@ -71,39 +72,6 @@ from govoplan_scheduling.backend.service import (
|
||||
|
||||
|
||||
router = APIRouter(prefix="/scheduling", tags=["scheduling"])
|
||||
CAPABILITY_ADDRESSES_LOOKUP = "addresses.lookup"
|
||||
|
||||
|
||||
def _capability_payload(value: object) -> dict[str, Any]:
|
||||
if dataclasses.is_dataclass(value):
|
||||
return dataclasses.asdict(value)
|
||||
if isinstance(value, dict):
|
||||
return dict(value)
|
||||
payload: dict[str, Any] = {}
|
||||
for key in (
|
||||
"contact_id",
|
||||
"address_book_id",
|
||||
"display_name",
|
||||
"email",
|
||||
"email_label",
|
||||
"organization",
|
||||
"role_title",
|
||||
"tags",
|
||||
"source_kind",
|
||||
"source_ref",
|
||||
"source_revision",
|
||||
"provenance",
|
||||
):
|
||||
if hasattr(value, key):
|
||||
payload[key] = getattr(value, key)
|
||||
return payload
|
||||
|
||||
|
||||
def _registry_capability(name: str) -> object | None:
|
||||
registry = get_registry()
|
||||
if registry is None or not hasattr(registry, "has_capability") or not registry.has_capability(name):
|
||||
return None
|
||||
return registry.capability(name)
|
||||
|
||||
|
||||
def _require_scope(principal: ApiPrincipal, scope: str) -> None:
|
||||
@@ -285,21 +253,43 @@ def api_submit_public_scheduling_participation(
|
||||
return validated
|
||||
|
||||
|
||||
@router.get("/address-lookup", response_model=SchedulingAddressLookupResponse)
|
||||
def api_lookup_scheduling_addresses(
|
||||
@router.get("/people", response_model=SchedulingPeopleSearchResponse)
|
||||
def api_search_scheduling_people(
|
||||
query: str = Query(min_length=1),
|
||||
limit: int = Query(default=25, ge=1, le=100),
|
||||
session: Session = Depends(get_session),
|
||||
principal: ApiPrincipal = Depends(get_api_principal),
|
||||
) -> SchedulingAddressLookupResponse:
|
||||
) -> SchedulingPeopleSearchResponse:
|
||||
_require_scheduling_writer(principal)
|
||||
capability = _registry_capability(CAPABILITY_ADDRESSES_LOOKUP)
|
||||
if capability is None or not hasattr(capability, "lookup"):
|
||||
return SchedulingAddressLookupResponse(available=False, candidates=[])
|
||||
candidates = getattr(capability, "lookup")(session, principal, query=query, limit=limit)
|
||||
return SchedulingAddressLookupResponse(
|
||||
available=True,
|
||||
candidates=[SchedulingAddressLookupCandidate.model_validate(_capability_payload(candidate)) for candidate in candidates],
|
||||
groups = search_visible_people(
|
||||
get_registry(),
|
||||
session,
|
||||
principal,
|
||||
query=query,
|
||||
limit=limit,
|
||||
)
|
||||
return SchedulingPeopleSearchResponse(
|
||||
groups=[
|
||||
SchedulingPeopleSearchGroup(
|
||||
key=group.key,
|
||||
label=group.label,
|
||||
candidates=[
|
||||
SchedulingPeopleSearchCandidate(
|
||||
selection_key=candidate.selection_key,
|
||||
kind=candidate.kind,
|
||||
reference_id=candidate.reference_id,
|
||||
display_name=candidate.display_name,
|
||||
email=candidate.email,
|
||||
source_module=candidate.source_module,
|
||||
source_label=candidate.source_label,
|
||||
source_revision=candidate.source_revision,
|
||||
description=candidate.description,
|
||||
)
|
||||
for candidate in group.candidates
|
||||
],
|
||||
)
|
||||
for group in groups
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user