release: bump version to 0.44.0

This commit is contained in:
linkong
2026-04-29 17:27:44 +08:00
parent 2da25376bd
commit 87594a95ff
54 changed files with 3665 additions and 2154 deletions

View File

@@ -17,6 +17,23 @@ from app.models.datasource import DataSource
from app.models.datasource_config import DataSourceConfig
from app.models.system_setting import SystemSetting
from app.models.user import User
from app.services.barentswatch import (
BarentsWatchConfig,
check_barentswatch_config,
check_barentswatch_connectivity,
get_barentswatch_datasource_record,
resolve_barentswatch_config,
)
from app.services.credential_guides import (
generate_credential_guide,
get_credential_guide,
reset_credential_guide,
)
from app.services.datasource_connectivity import (
build_builtin_connectivity_checksum,
save_connectivity_success,
)
from app.services.ai_client import AIProviderClient, get_ai_provider_client
from app.services.llm_provider_catalog import (
get_fallback_llm_provider_preset,
list_fallback_llm_provider_presets,
@@ -245,12 +262,7 @@ async def get_runtime_ai_provider_config(db: AsyncSession) -> dict:
async def get_barentswatch_config_record(db: AsyncSession) -> Optional[DataSourceConfig]:
result = await db.execute(
select(DataSourceConfig)
.where(DataSourceConfig.name == "barentswatch_vessels")
.where(DataSourceConfig.is_active.is_(True))
)
return result.scalar_one_or_none()
return await get_barentswatch_datasource_record(db)
async def serialize_external_integrations(db: AsyncSession) -> dict:
@@ -258,9 +270,9 @@ async def serialize_external_integrations(db: AsyncSession) -> dict:
runtime_setting = await get_setting_record(db, "external_integrations")
display_llm_config = ai_config["llm_config"] or DEFAULT_SETTINGS["external_integrations"]["ai_provider"]
barentswatch_record = await get_barentswatch_config_record(db)
yaml_config = get_data_sources_config()
barentswatch_auth = barentswatch_record.auth_config if barentswatch_record else {}
barentswatch_auth = barentswatch_auth or {}
resolved_barentswatch = await resolve_barentswatch_config(db)
return {
"ai_provider": {
"service_url": ai_config["service_url"],
@@ -277,14 +289,12 @@ async def serialize_external_integrations(db: AsyncSession) -> dict:
"source": "runtime" if runtime_setting else "env",
},
"barentswatch": {
"endpoint": (
barentswatch_record.endpoint
if barentswatch_record and barentswatch_record.endpoint
else yaml_config.get_yaml_url("barentswatch_vessels")
"endpoint": resolved_barentswatch.endpoint,
"client_id": barentswatch_auth.get("client_id") or resolved_barentswatch.client_id,
"client_secret": _mask_secret(
barentswatch_auth.get("client_secret") or resolved_barentswatch.client_secret
),
"client_id": barentswatch_auth.get("client_id") or "",
"client_secret": _mask_secret(barentswatch_auth.get("client_secret")),
"source": "datasource_config" if barentswatch_record else "default",
"source": resolved_barentswatch.credential_source,
},
}
@@ -328,7 +338,7 @@ async def save_external_integrations_payload(
description="BarentsWatch Live AIS credentials",
source_type="api",
endpoint=update.barentswatch.endpoint.strip() or default_endpoint,
auth_type="oauth_client_credentials",
auth_type="oauth_client",
auth_config={},
headers={},
config={},
@@ -343,7 +353,7 @@ async def save_external_integrations_payload(
current_auth["client_secret"] = update.barentswatch.client_secret
current_auth["client_id"] = update.barentswatch.client_id.strip()
barentswatch_record.endpoint = update.barentswatch.endpoint.strip() or default_endpoint
barentswatch_record.auth_type = "oauth_client_credentials"
barentswatch_record.auth_type = "oauth_client"
barentswatch_record.auth_config = current_auth
await db.commit()
@@ -461,6 +471,95 @@ async def get_external_integrations(
return {"integrations": await serialize_external_integrations(db)}
@router.get("/integrations/barentswatch/connectivity")
async def get_barentswatch_connectivity(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
return await check_barentswatch_connectivity(db)
@router.post("/integrations/barentswatch/connect")
async def connect_barentswatch_integration(
payload: BarentsWatchIntegrationUpdate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
current = await resolve_barentswatch_config(db)
config = BarentsWatchConfig(
endpoint=payload.endpoint.strip() or current.endpoint,
client_id=payload.client_id.strip() or current.client_id,
client_secret=(
""
if payload.clear_client_secret
else payload.client_secret or current.client_secret
),
credential_source="draft",
endpoint_source="draft",
)
result = await check_barentswatch_config(config)
if result.get("success"):
checksum, _context = await build_builtin_connectivity_checksum(
"barentswatch_vessels",
config.endpoint,
"none",
{},
{},
db,
credential_override={
"client_id": config.client_id,
"client_secret": config.client_secret,
},
)
validation = await save_connectivity_success(
db,
"barentswatch_vessels",
checksum,
result,
connected_by="connection_button",
)
await db.commit()
return {**result, "connected": True, "validation": validation}
return {**result, "connected": False}
@router.get("/credential-guides/{provider}")
async def read_credential_guide(
provider: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
try:
return {"guide": await get_credential_guide(db, provider)}
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@router.post("/credential-guides/{provider}/generate")
async def generate_provider_credential_guide(
provider: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
ai_client: AIProviderClient = Depends(get_ai_provider_client),
):
try:
return {"guide": await generate_credential_guide(db, provider, ai_client)}
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@router.post("/credential-guides/{provider}/reset")
async def reset_provider_credential_guide(
provider: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
try:
return {"guide": await reset_credential_guide(db, provider)}
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@router.get("/integrations/ai-provider/presets")
async def get_ai_provider_presets(
current_user: User = Depends(get_current_user),