2026-02-13 00:31:32 +05:30
|
|
|
"""Schemas for board webhook configuration and payload capture endpoints."""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from datetime import datetime
|
2026-03-03 22:31:58 -07:00
|
|
|
from typing import Annotated
|
2026-02-13 00:31:32 +05:30
|
|
|
from uuid import UUID
|
|
|
|
|
|
2026-03-03 22:31:58 -07:00
|
|
|
from pydantic import BeforeValidator
|
2026-02-13 00:31:32 +05:30
|
|
|
from sqlmodel import SQLModel
|
|
|
|
|
|
|
|
|
|
from app.schemas.common import NonEmptyStr
|
|
|
|
|
|
|
|
|
|
RUNTIME_ANNOTATION_TYPES = (datetime, UUID, NonEmptyStr)
|
|
|
|
|
|
|
|
|
|
|
2026-03-03 22:25:37 -07:00
|
|
|
def _normalize_secret(v: str | None) -> str | None:
|
|
|
|
|
"""Normalize blank/whitespace-only secrets to None."""
|
|
|
|
|
if v is None:
|
|
|
|
|
return None
|
|
|
|
|
stripped = v.strip()
|
|
|
|
|
return stripped or None
|
|
|
|
|
|
|
|
|
|
|
2026-03-03 22:31:58 -07:00
|
|
|
NormalizedSecret = Annotated[str | None, BeforeValidator(_normalize_secret)]
|
|
|
|
|
|
|
|
|
|
|
2026-02-13 00:31:32 +05:30
|
|
|
class BoardWebhookCreate(SQLModel):
|
|
|
|
|
"""Payload for creating a board webhook."""
|
|
|
|
|
|
|
|
|
|
description: NonEmptyStr
|
|
|
|
|
enabled: bool = True
|
2026-02-15 13:36:57 +05:30
|
|
|
agent_id: UUID | None = None
|
2026-03-03 22:31:58 -07:00
|
|
|
secret: NormalizedSecret = None
|
2026-03-04 01:35:25 -07:00
|
|
|
signature_header: str | None = None
|
2026-03-03 22:25:37 -07:00
|
|
|
|
2026-02-13 00:31:32 +05:30
|
|
|
|
|
|
|
|
class BoardWebhookUpdate(SQLModel):
|
|
|
|
|
"""Payload for updating a board webhook."""
|
|
|
|
|
|
|
|
|
|
description: NonEmptyStr | None = None
|
|
|
|
|
enabled: bool | None = None
|
2026-02-15 13:36:57 +05:30
|
|
|
agent_id: UUID | None = None
|
2026-03-03 22:31:58 -07:00
|
|
|
secret: NormalizedSecret = None
|
2026-03-04 01:35:25 -07:00
|
|
|
signature_header: str | None = None
|
2026-03-03 22:25:37 -07:00
|
|
|
|
2026-02-13 00:31:32 +05:30
|
|
|
|
|
|
|
|
class BoardWebhookRead(SQLModel):
|
|
|
|
|
"""Serialized board webhook configuration."""
|
|
|
|
|
|
|
|
|
|
id: UUID
|
|
|
|
|
board_id: UUID
|
2026-02-15 13:36:57 +05:30
|
|
|
agent_id: UUID | None = None
|
2026-02-13 00:31:32 +05:30
|
|
|
description: str
|
|
|
|
|
enabled: bool
|
2026-03-03 13:33:28 -07:00
|
|
|
has_secret: bool = False
|
2026-03-04 01:35:25 -07:00
|
|
|
signature_header: str | None = None
|
2026-02-13 00:31:32 +05:30
|
|
|
endpoint_path: str
|
|
|
|
|
endpoint_url: str | None = None
|
|
|
|
|
created_at: datetime
|
|
|
|
|
updated_at: datetime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BoardWebhookPayloadRead(SQLModel):
|
|
|
|
|
"""Serialized stored webhook payload."""
|
|
|
|
|
|
|
|
|
|
id: UUID
|
|
|
|
|
board_id: UUID
|
|
|
|
|
webhook_id: UUID
|
|
|
|
|
payload: dict[str, object] | list[object] | str | int | float | bool | None = None
|
|
|
|
|
headers: dict[str, str] | None = None
|
|
|
|
|
source_ip: str | None = None
|
|
|
|
|
content_type: str | None = None
|
|
|
|
|
received_at: datetime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BoardWebhookIngestResponse(SQLModel):
|
|
|
|
|
"""Response payload for inbound webhook ingestion."""
|
|
|
|
|
|
|
|
|
|
ok: bool = True
|
|
|
|
|
board_id: UUID
|
|
|
|
|
webhook_id: UUID
|
|
|
|
|
payload_id: UUID
|