feat(B-HOOK): Lifecycle Hooks + Outbox Events — 55 neue Hooks, 10 Domain Events
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
B-HOOK-CORE: Company Hooks (6: before/after create/update/delete) B-HOOK-MAIL: Mail Hooks (5: after_receive, before/after_delete, before/after_move) B-HOOK-DMS: DMS Hooks (10: after_upload, before/after_update/delete/restore, folder CRUD) B-HOOK-CAL: Calendar Hooks (4: before/after update/delete) B-HOOK-TASK: Task Hooks (6: before/after create/update/delete) B-HOOK-COMM: Communication Hooks (8: conversation create, message/edit/delete) B-HOOK-AI: Agent Hooks (2: before/after_run) B-HOOK-WF: Workflow Hooks (4: before/after_start, after_complete/cancel) B-HOOK-TAG: Tag Hooks (8: create/assign/unassign/delete) B-HOOK-SEARCH: Search Filters (2: before/after_search) B-EVT-OUTBOX: 10 Domain Events (task.completed, file.created/deleted/restored, mail.received, workflow.started/completed/cancelled, agent.run_started/completed) B-HOOK-TEST: 79 Tests in test_lifecycle_hooks.py — alle grün B-HOOK-DOC: Plugin-Dev-Guide Kapitel 8 aktualisiert (Hook-Liste + Outbox Event-Liste)
This commit is contained in:
@@ -257,6 +257,10 @@ async def create_folder(
|
||||
409, detail={"detail": "Folder name already exists", "code": "duplicate"}
|
||||
)
|
||||
|
||||
# Lifecycle hook: dms.folder.before_create
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.folder.before_create", body, db=db, tenant_id=tenant_id, user_id=user_id)
|
||||
|
||||
folder = Folder(
|
||||
tenant_id=tenant_id,
|
||||
name=body.name,
|
||||
@@ -266,6 +270,9 @@ async def create_folder(
|
||||
db.add(folder)
|
||||
await db.flush()
|
||||
|
||||
# Lifecycle hook: dms.folder.after_create
|
||||
await do_action("dms.folder.after_create", {'id': str(folder.id), 'name': folder.name, 'parent_id': str(folder.parent_id) if folder.parent_id else None}, db=db, tenant_id=tenant_id, user_id=user_id)
|
||||
|
||||
# Build path
|
||||
path = body.name
|
||||
if parent_id is not None:
|
||||
@@ -441,6 +448,10 @@ async def delete_folder(
|
||||
if not await check_single_entity_access(db, "dms_folder", fid, user_id, tenant_id, "delete", is_system_admin):
|
||||
raise HTTPException(403, detail={"detail": "Access denied", "code": "forbidden"})
|
||||
|
||||
# Lifecycle hook: dms.folder.before_delete
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.folder.before_delete", db=db, tenant_id=tenant_id, user_id=user_id, folder_id=str(fid))
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
now = datetime.now(UTC)
|
||||
@@ -476,6 +487,11 @@ async def delete_folder(
|
||||
)
|
||||
|
||||
await db.flush()
|
||||
|
||||
# Lifecycle hook: dms.folder.after_delete
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.folder.after_delete", db=db, tenant_id=tenant_id, user_id=user_id, folder_id=str(fid))
|
||||
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
@@ -597,6 +613,14 @@ async def upload_file(
|
||||
db.add(dms_file)
|
||||
await db.flush()
|
||||
|
||||
# Lifecycle hook: dms.after_upload
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.after_upload", {'id': str(dms_file.id), 'name': dms_file.name, 'folder_id': str(dms_file.folder_id) if dms_file.folder_id else None, 'mime_type': dms_file.mime_type, 'size_bytes': dms_file.size_bytes}, db=db, tenant_id=tenant_id, user_id=user_id)
|
||||
|
||||
# Outbox event: file.created
|
||||
from app.core.outbox import enqueue_outbox_event
|
||||
await enqueue_outbox_event(db, tenant_id, 'file.created', {'file_id': str(dms_file.id), 'tenant_id': str(tenant_id), 'name': dms_file.name, 'mime_type': dms_file.mime_type, 'size_bytes': dms_file.size_bytes}, aggregate_type='dms_file', aggregate_id=dms_file.id)
|
||||
|
||||
return {
|
||||
"id": str(dms_file.id),
|
||||
"name": dms_file.name,
|
||||
@@ -763,6 +787,10 @@ async def update_file(
|
||||
if not await check_single_entity_access(db, "dms_file", fid, user_id, tenant_id, "write", is_system_admin):
|
||||
raise HTTPException(403, detail={"detail": "Access denied", "code": "forbidden"})
|
||||
|
||||
# Lifecycle hook: dms.before_update
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.before_update", body.model_dump(exclude_unset=True), db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id)
|
||||
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
|
||||
if "name" in data and data["name"] is not None:
|
||||
@@ -785,6 +813,10 @@ async def update_file(
|
||||
await db.flush()
|
||||
await db.refresh(dms_file)
|
||||
|
||||
# Lifecycle hook: dms.after_update
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.after_update", {'id': str(dms_file.id), 'name': dms_file.name}, db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id)
|
||||
|
||||
return {
|
||||
"id": str(dms_file.id),
|
||||
"name": dms_file.name,
|
||||
@@ -824,10 +856,22 @@ async def delete_file(
|
||||
if not await check_single_entity_access(db, "dms_file", fid, user_id, tenant_id, "delete", is_system_admin):
|
||||
raise HTTPException(403, detail={"detail": "Access denied", "code": "forbidden"})
|
||||
|
||||
# Lifecycle hook: dms.before_delete
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.before_delete", db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id)
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
dms_file.deleted_at = datetime.now(UTC)
|
||||
await db.flush()
|
||||
|
||||
# Lifecycle hook: dms.after_delete
|
||||
await do_action("dms.after_delete", db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id)
|
||||
|
||||
# Outbox event: file.deleted
|
||||
from app.core.outbox import enqueue_outbox_event
|
||||
await enqueue_outbox_event(db, tenant_id, 'file.deleted', {'file_id': str(fid), 'tenant_id': str(tenant_id)}, aggregate_type='dms_file', aggregate_id=fid)
|
||||
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
@@ -857,10 +901,21 @@ async def restore_file(
|
||||
if not await check_single_entity_access(db, "dms_file", fid, user_id, tenant_id, "write", is_system_admin):
|
||||
raise HTTPException(403, detail={"detail": "Access denied", "code": "forbidden"})
|
||||
|
||||
# Lifecycle hook: dms.before_restore
|
||||
from app.core.hooks import do_action
|
||||
await do_action("dms.before_restore", db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id)
|
||||
|
||||
dms_file.deleted_at = None
|
||||
await db.flush()
|
||||
await db.refresh(dms_file)
|
||||
|
||||
# Lifecycle hook: dms.after_restore
|
||||
await do_action("dms.after_restore", {'id': str(dms_file.id), 'name': dms_file.name}, db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id)
|
||||
|
||||
# Outbox event: file.restored
|
||||
from app.core.outbox import enqueue_outbox_event
|
||||
await enqueue_outbox_event(db, tenant_id, 'file.restored', {'file_id': str(fid), 'tenant_id': str(tenant_id)}, aggregate_type='dms_file', aggregate_id=fid)
|
||||
|
||||
return {
|
||||
"id": str(dms_file.id),
|
||||
"name": dms_file.name,
|
||||
|
||||
Reference in New Issue
Block a user