fix(plugin): convert dependency errors to HTTPException 400, add config API
Bug 3: install_plugin() and activate_plugin() now catch dependency-related ValueErrors and raise HTTPException 400 with the error detail. Bug 4: Added get_plugin_config() and update_plugin_config() methods to the service layer for the plugin config API endpoints.
This commit is contained in:
@@ -6,6 +6,7 @@ import logging
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.audit import log_audit
|
||||
@@ -43,6 +44,7 @@ class PluginService:
|
||||
|
||||
Runs migrations, calls on_install hook, creates DB record.
|
||||
Idempotent: returns existing record if already installed.
|
||||
Checks that all declared dependencies are installed first.
|
||||
"""
|
||||
try:
|
||||
record = await self._registry.install(db, name)
|
||||
@@ -66,7 +68,13 @@ class PluginService:
|
||||
"message": "Plugin installed successfully",
|
||||
}
|
||||
except ValueError as exc:
|
||||
raise ValueError(str(exc)) from None
|
||||
msg = str(exc)
|
||||
if "dependencies" in msg.lower():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=msg,
|
||||
) from None
|
||||
raise ValueError(msg) from None
|
||||
except MigrationValidationError as exc:
|
||||
raise MigrationValidationError(str(exc)) from None
|
||||
|
||||
@@ -80,6 +88,7 @@ class PluginService:
|
||||
"""Activate a plugin by name.
|
||||
|
||||
Registers event listeners and routes. Idempotent.
|
||||
Checks that all declared dependencies are active first.
|
||||
"""
|
||||
try:
|
||||
record = await self._registry.activate(db, name)
|
||||
@@ -106,7 +115,13 @@ class PluginService:
|
||||
else "Plugin activated successfully",
|
||||
}
|
||||
except ValueError as exc:
|
||||
raise ValueError(str(exc)) from None
|
||||
msg = str(exc)
|
||||
if "dependencies" in msg.lower():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=msg,
|
||||
) from None
|
||||
raise ValueError(msg) from None
|
||||
|
||||
async def deactivate_plugin(
|
||||
self,
|
||||
@@ -187,6 +202,59 @@ class PluginService:
|
||||
except ValueError as exc:
|
||||
raise ValueError(str(exc)) from None
|
||||
|
||||
async def get_plugin_config(self, db: AsyncSession, name: str) -> dict[str, Any]:
|
||||
"""Get the configuration for a plugin.
|
||||
|
||||
Returns the plugin's config field parsed from JSON string.
|
||||
"""
|
||||
record = await self._registry._get_plugin_record(db, name)
|
||||
if record is None:
|
||||
raise ValueError(f"Plugin '{name}' is not installed")
|
||||
import json
|
||||
config_str = getattr(record, "config", None) or "{}"
|
||||
try:
|
||||
return json.loads(config_str) if isinstance(config_str, str) else config_str or {}
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
return {}
|
||||
|
||||
async def update_plugin_config(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
name: str,
|
||||
config: dict[str, Any],
|
||||
tenant_id: uuid.UUID | None = None,
|
||||
user_id: uuid.UUID | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Update the configuration for a plugin.
|
||||
|
||||
Stores the config as a JSON string in the plugin's config field.
|
||||
"""
|
||||
import json
|
||||
|
||||
record = await self._registry._get_plugin_record(db, name)
|
||||
if record is None:
|
||||
raise ValueError(f"Plugin '{name}' is not installed")
|
||||
|
||||
record.config = json.dumps(config)
|
||||
await db.flush()
|
||||
|
||||
if tenant_id and user_id:
|
||||
await log_audit(
|
||||
db,
|
||||
tenant_id,
|
||||
user_id,
|
||||
action="plugin.update_config",
|
||||
entity_type="plugin",
|
||||
entity_id=getattr(record, "id", None),
|
||||
changes={"name": name, "config": config},
|
||||
)
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"config": config,
|
||||
"message": "Plugin configuration updated successfully",
|
||||
}
|
||||
|
||||
def get_manifest_schema(self) -> dict[str, Any]:
|
||||
"""Return the manifest schema documentation."""
|
||||
from app.plugins.manifest import MANIFEST_SCHEMA_DOC
|
||||
|
||||
Reference in New Issue
Block a user