feat: Actions system — scheduled mutations on external services
Full-stack implementation of provider-scoped Actions with extensible executor architecture. First action type: Immich auto_organize (sort assets into albums by person, CLIP search, date range, favorites). Core: - ActionTypeDefinition registry + ActionExecutor ABC with execute/validate/dry-run - ImmichActionExecutor with multi-album support and client-side filtering - ImmichClient write methods: add/remove assets, create album, paginated search Server: - Action, ActionRule, ActionExecution DB models - Full CRUD API + manual execute + dry-run + execution history endpoints - APScheduler integration (interval + cron) for automated execution - Action type discovery API + provider people endpoint Frontend: - Actions page with CRUD, execute/dry-run buttons, inline rule editor - RuleEditor: person/album MultiEntitySelect pickers, criteria config - ExecutionHistory: expandable per-rule result details - MultiEntitySelect reusable component (searchable multi-pick palette) - Notification tracker album picker migrated to MultiEntitySelect - Fixed MdiIcon race condition (icons missing after cache-clearing reload)
This commit is contained in:
@@ -193,6 +193,7 @@ async def list_provider_capabilities():
|
||||
"commands": caps.commands,
|
||||
"supported_filters": caps.supported_filters,
|
||||
"webhook_based": caps.webhook_based,
|
||||
"action_types": caps.action_types,
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -351,6 +352,29 @@ async def test_provider(
|
||||
return {"ok": False, "message": f"Unknown provider type: {provider.type}"}
|
||||
|
||||
|
||||
@router.get("/{provider_id}/people")
|
||||
async def list_people(
|
||||
provider_id: int,
|
||||
user: User = Depends(get_current_user),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Fetch people from a service provider (Immich only)."""
|
||||
provider = await _get_user_provider(session, provider_id, user.id)
|
||||
|
||||
if provider.type == "immich":
|
||||
from notify_bridge_core.providers.immich.client import ImmichClient
|
||||
async with aiohttp.ClientSession() as http_session:
|
||||
client = ImmichClient(
|
||||
http_session,
|
||||
provider.config.get("url", ""),
|
||||
provider.config.get("api_key", ""),
|
||||
)
|
||||
people_dict = await client.get_people()
|
||||
return [{"id": pid, "name": name} for pid, name in people_dict.items()]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
@router.get("/{provider_id}/collections")
|
||||
async def list_collections(
|
||||
provider_id: int,
|
||||
|
||||
Reference in New Issue
Block a user