chore: fix all ruff lint errors + format — 0 errors, 306 tests pass

This commit is contained in:
leocrm-bot
2026-06-29 17:43:56 +02:00
parent 316f323ff4
commit a2452cc04b
81 changed files with 2317 additions and 1128 deletions
+14 -1
View File
@@ -1,3 +1,16 @@
"""Routes package."""
from app.routes import auth, users, roles, tenants, health, notifications, companies, contacts, import_export, plugins, ai_copilot, workflows
from app.routes import (
ai_copilot, # noqa: F401
auth, # noqa: F401
companies, # noqa: F401
contacts, # noqa: F401
health, # noqa: F401
import_export, # noqa: F401
notifications, # noqa: F401
plugins, # noqa: F401
roles, # noqa: F401
tenants, # noqa: F401
users, # noqa: F401
workflows, # noqa: F401
)
+13 -6
View File
@@ -7,12 +7,11 @@ import uuid
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.auth import check_permission
from app.core.db import get_db
from app.deps import get_current_user
from app.schemas.ai_copilot import (
CopilotQueryRequest,
CopilotExecuteRequest,
CopilotQueryRequest,
)
from app.services import ai_copilot_service
@@ -34,7 +33,9 @@ async def copilot_query(
user_id = uuid.UUID(current_user["user_id"])
result = await ai_copilot_service.process_query(
db, tenant_id, user_id,
db,
tenant_id,
user_id,
query=body.query,
conversation_id=body.conversation_id,
context=body.context,
@@ -65,7 +66,10 @@ async def copilot_execute(
role = current_user.get("role", "viewer")
result = await ai_copilot_service.execute_action(
db, tenant_id, user_id, role,
db,
tenant_id,
user_id,
role,
conversation_id=body.conversation_id,
action=body.action.model_dump(),
)
@@ -97,6 +101,9 @@ async def copilot_history(
user_id = uuid.UUID(current_user["user_id"])
return await ai_copilot_service.get_history(
db, tenant_id, user_id,
page=page, page_size=page_size,
db,
tenant_id,
user_id,
page=page,
page_size=page_size,
)
+10 -8
View File
@@ -3,19 +3,19 @@
from __future__ import annotations
import uuid
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import get_settings
from app.core.rate_limit import check_rate_limit, get_client_ip, reset_rate_limit
from app.core.auth import get_redis
from app.core.db import get_db
from app.deps import get_current_user
from app.core.rate_limit import check_rate_limit, get_client_ip, reset_rate_limit
from app.schemas.auth import (
LoginRequest, PasswordResetConfirm, PasswordResetRequest,
SwitchTenantRequest, AuthResponse,
LoginRequest,
PasswordResetConfirm,
PasswordResetRequest,
SwitchTenantRequest,
)
from app.services.auth_service import auth_service
@@ -64,6 +64,7 @@ async def login(
)
# Return auth info in body
from fastapi.responses import JSONResponse
resp = JSONResponse(
status_code=status.HTTP_200_OK,
content={
@@ -100,6 +101,7 @@ async def logout(
await auth_service.logout(redis, session_id)
from fastapi.responses import JSONResponse
resp = JSONResponse(
status_code=status.HTTP_200_OK,
content={"message": "Logged out"},
@@ -153,7 +155,7 @@ async def switch_tenant(
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail={"detail": "Invalid tenant_id", "code": "invalid_tenant_id"},
)
) from None
result = await auth_service.switch_tenant(db, redis, session_id, new_tenant_id)
if result is None:
@@ -180,7 +182,7 @@ async def password_reset_request(
):
"""Request password reset. Always returns 200 (no user enumeration)."""
ip = get_client_ip(request)
redis = get_redis()
redis = get_redis() # noqa: F841
await check_rate_limit(
f"auth:reset:{ip}",
@@ -200,7 +202,7 @@ async def password_reset_confirm(
):
"""Reset password with a valid token."""
ip = get_client_ip(request)
redis = get_redis()
redis = get_redis() # noqa: F841
await check_rate_limit(
f"auth:reset_confirm:{ip}",
+38 -14
View File
@@ -30,10 +30,14 @@ async def list_companies(
"""List companies with pagination, FTS search, industry filter, and sorting."""
tenant_id = uuid.UUID(current_user["tenant_id"])
result = await company_service.list_companies(
db, tenant_id,
page=page, page_size=page_size,
search=search, industry=industry,
sort_by=sort_by, sort_order=sort_order,
db,
tenant_id,
page=page,
page_size=page_size,
search=search,
industry=industry,
sort_by=sort_by,
sort_order=sort_order,
)
return result
@@ -72,7 +76,10 @@ async def export_companies(
if format == "csv":
csv_data = await company_service.export_companies_csv(
db, tenant_id, industry=industry, search=search,
db,
tenant_id,
industry=industry,
search=search,
)
return Response(
content=csv_data,
@@ -81,7 +88,10 @@ async def export_companies(
)
elif format == "xlsx":
xlsx_data = await company_service.export_companies_xlsx(
db, tenant_id, industry=industry, search=search,
db,
tenant_id,
industry=industry,
search=search,
)
return Response(
content=xlsx_data,
@@ -102,7 +112,9 @@ async def get_company(
try:
cid = uuid.UUID(company_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid company_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid company_id", "code": "invalid_id"}
) from None
data = await company_service.get_company_detail(db, tenant_id, cid)
if data is None:
@@ -128,7 +140,9 @@ async def update_company(
try:
cid = uuid.UUID(company_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid company_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid company_id", "code": "invalid_id"}
) from None
data = body.model_dump(exclude_unset=True)
result = await company_service.update_company(db, tenant_id, user_id, cid, data)
@@ -155,9 +169,13 @@ async def delete_company(
try:
cid = uuid.UUID(company_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid company_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid company_id", "code": "invalid_id"}
) from None
deleted = await company_service.soft_delete_company(db, tenant_id, user_id, cid, cascade=cascade)
deleted = await company_service.soft_delete_company(
db, tenant_id, user_id, cid, cascade=cascade
)
if not deleted:
raise HTTPException(404, detail={"detail": "Company not found", "code": "not_found"})
@@ -183,11 +201,13 @@ async def link_company_contact(
comp_id = uuid.UUID(company_id)
cont_id = uuid.UUID(contact_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"})
raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"}) from None
result = await company_service.link_contact(db, tenant_id, user_id, comp_id, cont_id)
if result is None:
raise HTTPException(404, detail={"detail": "Company or contact not found", "code": "not_found"})
raise HTTPException(
404, detail={"detail": "Company or contact not found", "code": "not_found"}
)
return result
@@ -210,7 +230,7 @@ async def unlink_company_contact(
comp_id = uuid.UUID(company_id)
cont_id = uuid.UUID(contact_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"})
raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"}) from None
unlinked = await company_service.unlink_contact(db, tenant_id, user_id, comp_id, cont_id)
if not unlinked:
@@ -230,11 +250,15 @@ async def get_company_emails(
try:
cid = uuid.UUID(company_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid company_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid company_id", "code": "invalid_id"}
) from None
# Verify company exists
from sqlalchemy import select
from app.models.company import Company
q = select(Company).where(
Company.id == cid,
Company.tenant_id == tenant_id,
+16 -6
View File
@@ -29,9 +29,13 @@ async def list_contacts(
"""List contacts with pagination and optional search."""
tenant_id = uuid.UUID(current_user["tenant_id"])
result = await contact_service.list_contacts(
db, tenant_id,
page=page, page_size=page_size,
search=search, sort_by=sort_by, sort_order=sort_order,
db,
tenant_id,
page=page,
page_size=page_size,
search=search,
sort_by=sort_by,
sort_order=sort_order,
)
return result
@@ -68,7 +72,9 @@ async def get_contact(
try:
cid = uuid.UUID(contact_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid contact_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid contact_id", "code": "invalid_id"}
) from None
data = await contact_service.get_contact_detail(db, tenant_id, cid)
if data is None:
@@ -94,7 +100,9 @@ async def update_contact(
try:
cid = uuid.UUID(contact_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid contact_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid contact_id", "code": "invalid_id"}
) from None
data = body.model_dump(exclude_unset=True)
result = await contact_service.update_contact(db, tenant_id, user_id, cid, data)
@@ -121,7 +129,9 @@ async def delete_contact(
try:
cid = uuid.UUID(contact_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid contact_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid contact_id", "code": "invalid_id"}
) from None
if gdpr:
deleted = await contact_service.gdpr_hard_delete_contact(db, tenant_id, user_id, cid)
+20 -5
View File
@@ -3,16 +3,21 @@
from __future__ import annotations
import uuid
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form, Query, Response, status
from fastapi import (
APIRouter,
Depends,
File,
Form,
HTTPException,
UploadFile,
)
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.auth import check_permission
from app.core.db import get_db
from app.deps import get_current_user
from app.services import import_export_service
from app.services import company_service
router = APIRouter(prefix="/api/v1", tags=["import_export"])
@@ -38,7 +43,12 @@ async def import_csv(
csv_content = content.decode("utf-8")
result = await import_export_service.import_csv(
db, tenant_id, user_id, csv_content, entity_type=entity_type, dry_run=False,
db,
tenant_id,
user_id,
csv_content,
entity_type=entity_type,
dry_run=False,
)
return result
@@ -62,6 +72,11 @@ async def import_csv_preview(
csv_content = content.decode("utf-8")
result = await import_export_service.import_csv(
db, tenant_id, user_id, csv_content, entity_type=entity_type, dry_run=True,
db,
tenant_id,
user_id,
csv_content,
entity_type=entity_type,
dry_run=True,
)
return result
+7 -3
View File
@@ -4,12 +4,14 @@ from __future__ import annotations
import uuid
from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_db
from app.core.notifications import (
get_unread_count, list_notifications, mark_notification_read,
get_unread_count,
list_notifications,
mark_notification_read,
)
from app.deps import get_current_user
@@ -41,7 +43,9 @@ async def mark_notification_read_endpoint(
try:
nid = uuid.UUID(notification_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid notification_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid notification_id", "code": "invalid_id"}
) from None
notif = await mark_notification_read(db, tenant_id, user_id, nid)
if notif is None:
+35 -15
View File
@@ -2,7 +2,7 @@
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_db
@@ -44,20 +44,26 @@ async def install_plugin(
Idempotent: returns 200 if already installed.
"""
import uuid as uuid_mod
service = get_plugin_service()
try:
result = await service.install_plugin(
db, name,
db,
name,
tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
user_id=uuid_mod.UUID(current_user["user_id"]),
)
return result
except ValueError as exc:
if "not found" in str(exc).lower():
raise HTTPException(404, detail={"detail": str(exc), "code": "plugin_not_found"})
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"})
raise HTTPException(
404, detail={"detail": str(exc), "code": "plugin_not_found"}
) from None
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None
except MigrationValidationError as exc:
raise HTTPException(422, detail={"detail": str(exc), "code": "migration_validation_error"})
raise HTTPException(
422, detail={"detail": str(exc), "code": "migration_validation_error"}
) from None
@router.post("/{name}/activate")
@@ -71,20 +77,26 @@ async def activate_plugin(
Idempotent: returns 200 if already active.
"""
import uuid as uuid_mod
service = get_plugin_service()
try:
result = await service.activate_plugin(
db, name,
db,
name,
tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
user_id=uuid_mod.UUID(current_user["user_id"]),
)
return result
except ValueError as exc:
if "not installed" in str(exc).lower():
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_not_installed"})
raise HTTPException(
400, detail={"detail": str(exc), "code": "plugin_not_installed"}
) from None
if "not found" in str(exc).lower():
raise HTTPException(404, detail={"detail": str(exc), "code": "plugin_not_found"})
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"})
raise HTTPException(
404, detail={"detail": str(exc), "code": "plugin_not_found"}
) from None
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None
@router.post("/{name}/deactivate")
@@ -98,18 +110,22 @@ async def deactivate_plugin(
Idempotent: returns 200 if already inactive.
"""
import uuid as uuid_mod
service = get_plugin_service()
try:
result = await service.deactivate_plugin(
db, name,
db,
name,
tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
user_id=uuid_mod.UUID(current_user["user_id"]),
)
return result
except ValueError as exc:
if "not found" in str(exc).lower():
raise HTTPException(404, detail={"detail": str(exc), "code": "plugin_not_found"})
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"})
raise HTTPException(
404, detail={"detail": str(exc), "code": "plugin_not_found"}
) from None
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None
@router.delete("/{name}")
@@ -124,10 +140,12 @@ async def uninstall_plugin(
Returns 200 with uninstalled status. Idempotent for already-uninstalled plugins.
"""
import uuid as uuid_mod
service = get_plugin_service()
try:
result = await service.uninstall_plugin(
db, name,
db,
name,
remove_data=remove_data,
tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
user_id=uuid_mod.UUID(current_user["user_id"]),
@@ -135,5 +153,7 @@ async def uninstall_plugin(
return result
except ValueError as exc:
if "not found" in str(exc).lower():
raise HTTPException(404, detail={"detail": str(exc), "code": "plugin_not_found"})
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"})
raise HTTPException(
404, detail={"detail": str(exc), "code": "plugin_not_found"}
) from None
raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None
+18 -6
View File
@@ -4,8 +4,7 @@ from __future__ import annotations
import uuid
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import Response
from fastapi import APIRouter, Depends, HTTPException, Response, status
from fastapi.responses import JSONResponse
from sqlalchemy.ext.asyncio import AsyncSession
@@ -37,7 +36,11 @@ async def create_role(
"""Create a custom role (admin only)."""
tenant_id = uuid.UUID(current_user["tenant_id"])
role = await role_service.create_role(
db, tenant_id, body.name, body.permissions, body.field_permissions,
db,
tenant_id,
body.name,
body.permissions,
body.field_permissions,
)
return JSONResponse(
status_code=status.HTTP_201_CREATED,
@@ -62,10 +65,17 @@ async def update_role(
try:
rid = uuid.UUID(role_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid role_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid role_id", "code": "invalid_id"}
) from None
role = await role_service.update_role(
db, tenant_id, rid, body.name, body.permissions, body.field_permissions,
db,
tenant_id,
rid,
body.name,
body.permissions,
body.field_permissions,
)
if role is None:
raise HTTPException(404, detail={"detail": "Role not found", "code": "not_found"})
@@ -89,7 +99,9 @@ async def delete_role(
try:
rid = uuid.UUID(role_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid role_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid role_id", "code": "invalid_id"}
) from None
success = await role_service.delete_role(db, tenant_id, rid)
if not success:
+6 -4
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import uuid
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_db
@@ -51,7 +51,9 @@ async def list_tenant_users(
try:
tid = uuid.UUID(tenant_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid tenant_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid tenant_id", "code": "invalid_id"}
) from None
users = await tenant_service.list_tenant_users(db, tid)
return {"items": users}
@@ -69,7 +71,7 @@ async def assign_user_to_tenant(
tid = uuid.UUID(tenant_id)
uid = uuid.UUID(body.user_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"})
raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"}) from None
ut = await tenant_service.assign_user_to_tenant(db, tid, uid)
await tenant_service.assign_user_to_tenant(db, tid, uid)
return {"message": "User assigned to tenant"}
+40 -11
View File
@@ -5,14 +5,13 @@ from __future__ import annotations
import uuid
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi import Response
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.audit import log_audit
from app.core.db import get_db
from app.core.notifications import create_notification
from app.deps import get_current_user, require_admin, get_tenant_id, get_current_user_id
from app.deps import get_current_user, require_admin
from app.schemas.user import UserCreate, UserUpdate
from app.services.user_service import user_service
@@ -43,18 +42,32 @@ async def create_user(
user_id = uuid.UUID(current_user["user_id"])
user = await user_service.create_user(
db, tenant_id, body.email, body.name, body.password, body.role, body.is_active,
db,
tenant_id,
body.email,
body.name,
body.password,
body.role,
body.is_active,
)
# Audit log
await log_audit(
db, tenant_id, user_id, "create", "user", user.id,
db,
tenant_id,
user_id,
"create",
"user",
user.id,
changes={"email": body.email, "name": body.name, "role": body.role},
)
# Notification
await create_notification(
db, tenant_id, user.id, "info",
db,
tenant_id,
user.id,
"info",
"Account created",
f"Your account has been created by {current_user['name']}.",
)
@@ -80,7 +93,9 @@ async def get_user(
try:
uid = uuid.UUID(user_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid user_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid user_id", "code": "invalid_id"}
) from None
user = await user_service.get_user(db, tenant_id, uid)
if user is None:
@@ -109,7 +124,9 @@ async def update_user(
try:
uid = uuid.UUID(user_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid user_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid user_id", "code": "invalid_id"}
) from None
changes: dict[str, Any] = {}
if body.name is not None:
@@ -120,7 +137,12 @@ async def update_user(
changes["is_active"] = body.is_active
user = await user_service.update_user(
db, tenant_id, uid, body.name, body.role, body.is_active,
db,
tenant_id,
uid,
body.name,
body.role,
body.is_active,
)
if user is None:
raise HTTPException(404, detail={"detail": "User not found", "code": "not_found"})
@@ -149,7 +171,9 @@ async def delete_user(
try:
uid = uuid.UUID(user_id)
except ValueError:
raise HTTPException(400, detail={"detail": "Invalid user_id", "code": "invalid_id"})
raise HTTPException(
400, detail={"detail": "Invalid user_id", "code": "invalid_id"}
) from None
# Get user snapshot for audit before deletion
user = await user_service.get_user(db, tenant_id, uid)
@@ -161,7 +185,12 @@ async def delete_user(
raise HTTPException(404, detail={"detail": "User not found", "code": "not_found"})
await log_audit(
db, tenant_id, acting_user_id, "delete", "user", uid,
db,
tenant_id,
acting_user_id,
"delete",
"user",
uid,
changes={"email": user.email, "name": user.name},
)
+20 -8
View File
@@ -10,7 +10,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.core.auth import check_permission
from app.core.db import get_db
from app.deps import get_current_user
from app.schemas.workflow import WorkflowCreate, WorkflowUpdate, InstanceCreate, AdvanceRequest
from app.schemas.workflow import AdvanceRequest, InstanceCreate, WorkflowCreate, WorkflowUpdate
from app.services import workflow_service
router = APIRouter(prefix="/api/v1/workflows", tags=["workflows"])
@@ -18,6 +18,7 @@ router = APIRouter(prefix="/api/v1/workflows", tags=["workflows"])
# ─── Workflow CRUD ───
@router.get("")
async def list_workflows(
page: int = Query(1, ge=1),
@@ -29,8 +30,10 @@ async def list_workflows(
"""List workflows with pagination."""
tenant_id = uuid.UUID(current_user["tenant_id"])
return await workflow_service.list_workflows(
db, tenant_id,
page=page, page_size=page_size,
db,
tenant_id,
page=page,
page_size=page_size,
is_active=is_active,
)
@@ -67,8 +70,10 @@ async def list_instances(
"""List workflow instances with optional status filter."""
tenant_id = uuid.UUID(current_user["tenant_id"])
return await workflow_service.list_instances(
db, tenant_id,
page=page, page_size=page_size,
db,
tenant_id,
page=page,
page_size=page_size,
status_filter=status,
)
@@ -146,6 +151,7 @@ async def delete_workflow(
# ─── Instance endpoints ───
@router.post("/{workflow_id}/instances", status_code=status.HTTP_201_CREATED)
async def create_instance(
workflow_id: str,
@@ -158,7 +164,9 @@ async def create_instance(
user_id = uuid.UUID(current_user["user_id"])
result = await workflow_service.create_instance(
db, tenant_id, user_id,
db,
tenant_id,
user_id,
workflow_id=workflow_id,
context=body.context,
timeout_hours=body.timeout_hours,
@@ -204,7 +212,9 @@ async def advance_instance(
user_id = uuid.UUID(current_user["user_id"])
result = await workflow_service.advance_instance(
db, tenant_id, user_id,
db,
tenant_id,
user_id,
instance_id=instance_id,
decision=body.decision,
comment=body.comment,
@@ -233,7 +243,9 @@ async def cancel_instance(
user_id = uuid.UUID(current_user["user_id"])
result = await workflow_service.cancel_instance(
db, tenant_id, user_id,
db,
tenant_id,
user_id,
instance_id=instance_id,
)
if result is None: