feat(connectors): add managed file and PostgreSQL origins
Module Package Release / publish-packages (push) Successful in 12s

This commit is contained in:
2026-08-21 19:29:58 +02:00
parent e6ab8291ec
commit 2c2b11f860
13 changed files with 2082 additions and 59 deletions
+131 -3
View File
@@ -32,6 +32,7 @@ from govoplan_connectors.backend.schemas import (
FeedImportRequest,
FeedPublicationEntryPayload,
FeedRenderPayload,
ManagedFileSourceCreateRequest,
SanctionsAcquisitionRunListResponse,
SanctionsAcquisitionRunResponse,
SanctionsRefreshResponse,
@@ -40,6 +41,7 @@ from govoplan_connectors.backend.schemas import (
SanctionsSourceListResponse,
SanctionsSourceResponse,
SnapshotCreateRequest,
SqlSourceCreateRequest,
TabularColumnResponse,
TabularHealthResponse,
TabularPreviewDiagnosticResponse,
@@ -460,12 +462,82 @@ def api_create_tabular_snapshot(
return _source_response(source)
@router.post(
"/tabular-sources/files",
response_model=TabularSourceResponse,
status_code=status.HTTP_201_CREATED,
)
def api_create_managed_file_source(
payload: ManagedFileSourceCreateRequest,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> TabularSourceResponse:
_require_any_scope(principal, WRITE_SCOPE, ADMIN_SCOPE)
try:
source = provider.create_file_source(
session,
principal,
name=payload.name,
source_name=payload.source_name,
description=payload.description,
file_asset_id=payload.file_asset_id,
file_version_id=payload.file_version_id,
delimiter=payload.delimiter,
sheet_name=payload.sheet_name,
)
except TabularSourceError as exc:
raise _http_error(exc) from exc
_audit_tabular_source_change(
session,
principal,
source,
operation="created",
)
session.commit()
return _source_response(source)
@router.post(
"/tabular-sources/sql",
response_model=TabularSourceResponse,
status_code=status.HTTP_201_CREATED,
)
def api_create_sql_source(
payload: SqlSourceCreateRequest,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> TabularSourceResponse:
_require_any_scope(principal, WRITE_SCOPE, ADMIN_SCOPE)
try:
source = provider.create_sql_source(
session,
principal,
name=payload.name,
source_name=payload.source_name,
description=payload.description,
configuration_id=payload.configuration_id,
schema_name=payload.schema_name,
table_name=payload.table_name,
)
except TabularSourceError as exc:
raise _http_error(exc) from exc
_audit_tabular_source_change(
session,
principal,
source,
operation="created",
)
session.commit()
return _source_response(source)
@router.get(
"/tabular-sources/{source_id}/preview",
response_model=TabularSourcePreviewResponse,
)
def api_preview_tabular_source(
source_id: str,
kind: Annotated[str, Query(pattern=r"^(snapshot|file|sql)$")] = "snapshot",
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
max_bytes: int = Query(default=1_000_000, ge=2, le=5_000_000),
@@ -479,7 +551,7 @@ def api_preview_tabular_source(
session,
principal,
request=TabularReadRequest(
source_ref=f"snapshot:{source_id}",
source_ref=f"{kind}:{source_id}",
limit=limit,
offset=offset,
max_bytes=max_bytes,
@@ -510,17 +582,47 @@ def api_preview_tabular_source(
)
@router.post(
"/tabular-sources/{source_id}/refresh",
response_model=TabularSourceResponse,
)
def api_refresh_tabular_source(
source_id: str,
kind: Annotated[str, Query(pattern=r"^(file|sql)$")],
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> TabularSourceResponse:
_require_any_scope(principal, WRITE_SCOPE, ADMIN_SCOPE)
try:
source = provider.refresh_source(
session,
principal,
source_ref=f"{kind}:{source_id}",
)
except TabularSourceError as exc:
raise _http_error(exc) from exc
_audit_tabular_source_change(
session,
principal,
source,
operation="refreshed",
)
session.commit()
return _source_response(source)
@router.delete(
"/tabular-sources/{source_id}",
response_model=TabularSourceDeleteResponse,
)
def api_delete_tabular_source(
source_id: str,
kind: Annotated[str, Query(pattern=r"^(snapshot|file|sql)$")] = "snapshot",
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> TabularSourceDeleteResponse:
_require_any_scope(principal, WRITE_SCOPE, ADMIN_SCOPE)
source_ref = f"snapshot:{source_id}"
source_ref = f"{kind}:{source_id}"
try:
source = provider.delete_snapshot(
session,
@@ -534,7 +636,7 @@ def api_delete_tabular_source(
tenant_id=principal.tenant_id,
user_id=getattr(principal.user, "id", None),
api_key_id=principal.api_key_id,
action="connectors.tabular_snapshot.deleted",
action="connectors.tabular_source.deleted",
object_type="connector_tabular_source",
object_id=source_ref,
details={"source_name": source.source_name, "fingerprint": source.fingerprint},
@@ -928,6 +1030,32 @@ def _source_response(source: TabularSource) -> TabularSourceResponse:
)
def _audit_tabular_source_change(
session: Session,
principal: ApiPrincipal,
source: TabularSource,
*,
operation: str,
) -> None:
audit_event(
session,
tenant_id=principal.tenant_id,
user_id=getattr(principal.user, "id", None),
api_key_id=principal.api_key_id,
action=f"connectors.tabular_source.{operation}",
object_type="connector_tabular_source",
object_id=source.ref,
details={
"provider": source.provider,
"source_name": source.source_name,
"fingerprint": source.fingerprint,
"schema_version": source.schema_version,
"row_count": source.row_count,
"source_mode": source.source_mode,
},
)
def _sanctions_snapshot_response(
snapshot: SanctionsSnapshotReference,
) -> SanctionsSnapshotResponse: