mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-02 19:55:18 +02:00
feat(gateway): enhance WhatsApp account management and connection handling
This commit is contained in:
parent
2d1a6be776
commit
a151e8f729
3 changed files with 399 additions and 210 deletions
|
|
@ -169,6 +169,10 @@ class UpdateBindingSearchSpaceRequest(BaseModel):
|
|||
search_space_id: int
|
||||
|
||||
|
||||
class UpdateAccountSearchSpaceRequest(BaseModel):
|
||||
search_space_id: int
|
||||
|
||||
|
||||
def _classify_telegram_event(payload: dict[str, Any]) -> str:
|
||||
if "message" in payload:
|
||||
return "message"
|
||||
|
|
@ -704,21 +708,27 @@ async def list_bindings(
|
|||
|
||||
@router.get("/connections")
|
||||
async def list_connections(
|
||||
platform: ExternalChatPlatform | None = None,
|
||||
user: User = Depends(current_active_user),
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
) -> list[dict[str, Any]]:
|
||||
filters = [
|
||||
ExternalChatBinding.user_id == user.id,
|
||||
ExternalChatBinding.state.in_(
|
||||
[ExternalChatBindingState.BOUND, ExternalChatBindingState.SUSPENDED]
|
||||
),
|
||||
]
|
||||
if platform is not None:
|
||||
filters.append(ExternalChatAccount.platform == platform)
|
||||
|
||||
result = await session.execute(
|
||||
select(ExternalChatBinding, ExternalChatAccount)
|
||||
.join(ExternalChatAccount, ExternalChatBinding.account_id == ExternalChatAccount.id)
|
||||
.where(
|
||||
ExternalChatBinding.user_id == user.id,
|
||||
ExternalChatBinding.state.in_(
|
||||
[ExternalChatBindingState.BOUND, ExternalChatBindingState.SUSPENDED]
|
||||
),
|
||||
)
|
||||
.where(*filters)
|
||||
)
|
||||
|
||||
connections: list[dict[str, Any]] = []
|
||||
baileys_account_ids: set[int] = set()
|
||||
for binding, account in result.all():
|
||||
binding_metadata = binding.external_metadata or {}
|
||||
kind = str(binding_metadata.get("kind") or "")
|
||||
|
|
@ -728,6 +738,10 @@ async def list_connections(
|
|||
account_state = account.cursor_state or {}
|
||||
workspace_name = None
|
||||
workspace_id = None
|
||||
route_type = "binding"
|
||||
connection_id = binding.id
|
||||
search_space_id = binding.search_space_id
|
||||
display_name = binding.external_display_name or binding.external_username
|
||||
if account.platform == ExternalChatPlatform.SLACK:
|
||||
workspace_name = account_state.get("team_name")
|
||||
workspace_id = account_state.get("team_id")
|
||||
|
|
@ -737,17 +751,30 @@ async def list_connections(
|
|||
elif account.platform == ExternalChatPlatform.WHATSAPP:
|
||||
workspace_name = account_state.get("display_phone_number")
|
||||
workspace_id = account_state.get("phone_number_id")
|
||||
if account.mode == ExternalChatAccountMode.SELF_HOST_BYO:
|
||||
if int(account.id) in baileys_account_ids:
|
||||
continue
|
||||
baileys_account_ids.add(int(account.id))
|
||||
route_type = "account"
|
||||
connection_id = account.id
|
||||
search_space_id = account.owner_search_space_id or binding.search_space_id
|
||||
display_name = "WhatsApp Bridge"
|
||||
|
||||
connections.append(
|
||||
{
|
||||
"id": binding.id,
|
||||
"id": connection_id,
|
||||
"account_id": account.id,
|
||||
"route_type": route_type,
|
||||
"platform": account.platform.value,
|
||||
"mode": account.mode.value,
|
||||
"state": binding.state.value,
|
||||
"search_space_id": binding.search_space_id,
|
||||
"display_name": binding.external_display_name
|
||||
or binding.external_username
|
||||
or workspace_name,
|
||||
"external_username": binding.external_username,
|
||||
"search_space_id": search_space_id,
|
||||
"display_name": display_name or workspace_name,
|
||||
"external_username": (
|
||||
None
|
||||
if account.mode == ExternalChatAccountMode.SELF_HOST_BYO
|
||||
else binding.external_username
|
||||
),
|
||||
"workspace_name": workspace_name,
|
||||
"workspace_id": workspace_id,
|
||||
"health_status": account.health_status.value,
|
||||
|
|
@ -755,6 +782,37 @@ async def list_connections(
|
|||
}
|
||||
)
|
||||
|
||||
if platform is None or platform == ExternalChatPlatform.WHATSAPP:
|
||||
account_result = await session.execute(
|
||||
select(ExternalChatAccount).where(
|
||||
ExternalChatAccount.owner_user_id == user.id,
|
||||
ExternalChatAccount.platform == ExternalChatPlatform.WHATSAPP,
|
||||
ExternalChatAccount.mode == ExternalChatAccountMode.SELF_HOST_BYO,
|
||||
ExternalChatAccount.owner_search_space_id.is_not(None),
|
||||
)
|
||||
)
|
||||
for account in account_result.scalars():
|
||||
if int(account.id) in baileys_account_ids:
|
||||
continue
|
||||
account_state = account.cursor_state or {}
|
||||
connections.append(
|
||||
{
|
||||
"id": account.id,
|
||||
"account_id": account.id,
|
||||
"route_type": "account",
|
||||
"platform": account.platform.value,
|
||||
"mode": account.mode.value,
|
||||
"state": "bound",
|
||||
"search_space_id": account.owner_search_space_id,
|
||||
"display_name": "WhatsApp Bridge",
|
||||
"external_username": None,
|
||||
"workspace_name": account_state.get("display_phone_number"),
|
||||
"workspace_id": account_state.get("phone_number_id"),
|
||||
"health_status": account.health_status.value,
|
||||
"suspended_reason": account.suspended_reason,
|
||||
}
|
||||
)
|
||||
|
||||
return connections
|
||||
|
||||
|
||||
|
|
@ -807,6 +865,44 @@ async def update_binding_search_space(
|
|||
return {"ok": True}
|
||||
|
||||
|
||||
@router.patch("/accounts/{account_id}/search-space")
|
||||
async def update_gateway_account_search_space(
|
||||
account_id: int,
|
||||
body: UpdateAccountSearchSpaceRequest,
|
||||
user: User = Depends(current_active_user),
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
) -> dict[str, bool]:
|
||||
account = await session.get(ExternalChatAccount, account_id)
|
||||
if (
|
||||
account is None
|
||||
or account.owner_user_id != user.id
|
||||
or account.platform != ExternalChatPlatform.WHATSAPP
|
||||
or account.mode != ExternalChatAccountMode.SELF_HOST_BYO
|
||||
):
|
||||
raise HTTPException(status_code=404, detail="Gateway account not found")
|
||||
|
||||
await check_search_space_access(session, user, body.search_space_id)
|
||||
account.owner_search_space_id = body.search_space_id
|
||||
account.updated_at = datetime.now(UTC)
|
||||
|
||||
result = await session.execute(
|
||||
select(ExternalChatBinding).where(
|
||||
ExternalChatBinding.account_id == account.id,
|
||||
ExternalChatBinding.user_id == user.id,
|
||||
ExternalChatBinding.state.in_(
|
||||
[ExternalChatBindingState.BOUND, ExternalChatBindingState.SUSPENDED]
|
||||
),
|
||||
)
|
||||
)
|
||||
for binding in result.scalars():
|
||||
binding.search_space_id = body.search_space_id
|
||||
binding.new_chat_thread_id = None
|
||||
binding.updated_at = datetime.now(UTC)
|
||||
|
||||
await session.commit()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.delete("/bindings/{binding_id}")
|
||||
async def delete_binding(
|
||||
binding_id: int,
|
||||
|
|
@ -821,6 +917,41 @@ async def delete_binding(
|
|||
return {"ok": True}
|
||||
|
||||
|
||||
@router.delete("/accounts/{account_id}")
|
||||
async def delete_gateway_account(
|
||||
account_id: int,
|
||||
user: User = Depends(current_active_user),
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
) -> dict[str, bool]:
|
||||
account = await session.get(ExternalChatAccount, account_id)
|
||||
if (
|
||||
account is None
|
||||
or account.owner_user_id != user.id
|
||||
or account.platform != ExternalChatPlatform.WHATSAPP
|
||||
or account.mode != ExternalChatAccountMode.SELF_HOST_BYO
|
||||
):
|
||||
raise HTTPException(status_code=404, detail="Gateway account not found")
|
||||
|
||||
result = await session.execute(
|
||||
select(ExternalChatBinding).where(
|
||||
ExternalChatBinding.account_id == account.id,
|
||||
ExternalChatBinding.user_id == user.id,
|
||||
ExternalChatBinding.state.in_(
|
||||
[ExternalChatBindingState.BOUND, ExternalChatBindingState.SUSPENDED]
|
||||
),
|
||||
)
|
||||
)
|
||||
for binding in result.scalars():
|
||||
revoke_binding(binding)
|
||||
|
||||
account.owner_search_space_id = None
|
||||
account.suspended_at = datetime.now(UTC)
|
||||
account.suspended_reason = "disconnected"
|
||||
account.updated_at = datetime.now(UTC)
|
||||
await session.commit()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.post("/bindings/{binding_id}/resume")
|
||||
async def resume_external_chat_binding(
|
||||
binding_id: int,
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ async def request_pairing_code(
|
|||
account.mode = ExternalChatAccountMode.SELF_HOST_BYO
|
||||
account.owner_search_space_id = body.search_space_id
|
||||
account.health_status = ExternalChatHealthStatus.UNKNOWN
|
||||
account.suspended_at = None
|
||||
account.suspended_reason = None
|
||||
account.last_health_check_at = datetime.now(UTC)
|
||||
await session.commit()
|
||||
await session.refresh(account)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue