mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-13 11:22:14 +02:00
fix: scope workflow run to org rather than user
This commit is contained in:
parent
4989bab1e9
commit
43737c67dc
29 changed files with 218 additions and 158 deletions
|
|
@ -99,7 +99,6 @@ class ARIProvider(TelephonyProvider):
|
|||
[
|
||||
f"workflow_run_id={workflow_run_id}",
|
||||
f"workflow_id={kwargs.get('workflow_id', '')}",
|
||||
f"user_id={kwargs.get('user_id', '')}",
|
||||
],
|
||||
)
|
||||
),
|
||||
|
|
@ -179,7 +178,7 @@ class ARIProvider(TelephonyProvider):
|
|||
return True
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""ARI does not use webhook responses - call control is via REST API."""
|
||||
logger.warning(
|
||||
|
|
@ -241,7 +240,7 @@ class ARIProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -253,7 +252,9 @@ class ARIProvider(TelephonyProvider):
|
|||
from api.services.pipecat.run_pipeline import run_pipeline_telephony
|
||||
|
||||
# Get channel_id from workflow run context
|
||||
workflow_run = await db_client.get_workflow_run(workflow_run_id, user_id)
|
||||
workflow_run = await db_client.get_workflow_run(
|
||||
workflow_run_id, organization_id=organization_id
|
||||
)
|
||||
channel_id = ""
|
||||
if workflow_run and workflow_run.gathered_context:
|
||||
channel_id = workflow_run.gathered_context.get("call_id", "")
|
||||
|
|
@ -267,7 +268,7 @@ class ARIProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=channel_id,
|
||||
transport_kwargs={"channel_id": channel_id},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,10 @@ class CloudonixProvider(TelephonyProvider):
|
|||
logger.info(
|
||||
f"Selected phone number {from_number} for outbound call to {to_number}"
|
||||
)
|
||||
workflow_id, user_id = kwargs["workflow_id"], kwargs["user_id"]
|
||||
workflow_id, organization_id = (
|
||||
kwargs["workflow_id"],
|
||||
kwargs["organization_id"],
|
||||
)
|
||||
|
||||
# Prepare call data using Cloudonix callObject schema
|
||||
# Note: 'caller-id' is REQUIRED by Cloudonix API
|
||||
|
|
@ -130,7 +133,7 @@ class CloudonixProvider(TelephonyProvider):
|
|||
"cxml": f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Response>
|
||||
<Connect>
|
||||
<Stream url="{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{user_id}/{workflow_run_id}"></Stream>
|
||||
<Stream url="{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}"></Stream>
|
||||
</Connect>
|
||||
<Pause length="40"/>
|
||||
</Response>""",
|
||||
|
|
@ -408,7 +411,7 @@ class CloudonixProvider(TelephonyProvider):
|
|||
}
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""
|
||||
Dummy implementation - Cloudonix doesn't use webhook responses.
|
||||
|
|
@ -430,7 +433,7 @@ class CloudonixProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -502,7 +505,7 @@ class CloudonixProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_id,
|
||||
transport_kwargs={"call_id": call_id, "stream_sid": stream_sid},
|
||||
)
|
||||
|
|
@ -517,7 +520,6 @@ class CloudonixProvider(TelephonyProvider):
|
|||
*,
|
||||
organization_id: int,
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
workflow_run_id: int,
|
||||
params: Dict[str, str],
|
||||
) -> None:
|
||||
|
|
@ -671,7 +673,7 @@ class CloudonixProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_session,
|
||||
transport_kwargs={
|
||||
"call_id": call_session,
|
||||
|
|
|
|||
|
|
@ -238,13 +238,13 @@ class PlivoProvider(TelephonyProvider):
|
|||
return any(hmac.compare_digest(computed, candidate) for candidate in candidates)
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
_, wss_backend_endpoint = await get_backend_endpoints()
|
||||
|
||||
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Response>
|
||||
<Stream bidirectional="true" keepCallAlive="true" contentType="audio/x-mulaw;rate=8000">{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{user_id}/{workflow_run_id}</Stream>
|
||||
<Stream bidirectional="true" keepCallAlive="true" contentType="audio/x-mulaw;rate=8000">{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}</Stream>
|
||||
</Response>"""
|
||||
|
||||
async def get_call_cost(self, call_id: str) -> Dict[str, Any]:
|
||||
|
|
@ -309,7 +309,7 @@ class PlivoProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
from api.services.pipecat.run_pipeline import run_pipeline_telephony
|
||||
|
|
@ -348,7 +348,7 @@ class PlivoProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_id,
|
||||
transport_kwargs={"stream_id": stream_id, "call_id": call_id},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ async def _handle_plivo_status_callback(
|
|||
@router.post("/plivo-xml", include_in_schema=False)
|
||||
async def handle_plivo_xml_webhook(
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
workflow_run_id: int,
|
||||
organization_id: int,
|
||||
request: Request,
|
||||
|
|
@ -110,7 +109,7 @@ async def handle_plivo_xml_webhook(
|
|||
)
|
||||
|
||||
response_content = await provider.get_webhook_response(
|
||||
workflow_id, user_id, workflow_run_id
|
||||
workflow_id, organization_id, workflow_run_id
|
||||
)
|
||||
return HTMLResponse(content=response_content, media_type="application/xml")
|
||||
|
||||
|
|
|
|||
|
|
@ -101,10 +101,10 @@ class TelnyxProvider(TelephonyProvider):
|
|||
|
||||
# Build the WebSocket stream URL for inline audio streaming
|
||||
workflow_id = kwargs.get("workflow_id")
|
||||
user_id = kwargs.get("user_id")
|
||||
organization_id = kwargs.get("organization_id")
|
||||
stream_url = (
|
||||
f"{wss_backend_endpoint}/api/v1/telephony/ws"
|
||||
f"/{workflow_id}/{user_id}/{workflow_run_id}"
|
||||
f"/{workflow_id}/{organization_id}/{workflow_run_id}"
|
||||
)
|
||||
|
||||
# Build the webhook URL for status callbacks
|
||||
|
|
@ -267,7 +267,7 @@ class TelnyxProvider(TelephonyProvider):
|
|||
return False
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""Not used for Telnyx — streaming is inline with the dial request."""
|
||||
return ""
|
||||
|
|
@ -338,7 +338,7 @@ class TelnyxProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
"""Handle Telnyx WebSocket connection for real-time audio.
|
||||
|
|
@ -406,7 +406,7 @@ class TelnyxProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_control_id,
|
||||
transport_kwargs={
|
||||
"stream_id": stream_id,
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ class TwilioProvider(TelephonyProvider):
|
|||
return validator.validate(url, params, signature)
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""
|
||||
Generate TwiML response for starting a call session.
|
||||
|
|
@ -176,7 +176,7 @@ class TwilioProvider(TelephonyProvider):
|
|||
twiml_content = f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Response>
|
||||
<Connect>
|
||||
<Stream url="{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{user_id}/{workflow_run_id}"></Stream>
|
||||
<Stream url="{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}"></Stream>
|
||||
</Connect>
|
||||
<Pause length="40"/>
|
||||
</Response>"""
|
||||
|
|
@ -274,7 +274,7 @@ class TwilioProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -325,7 +325,7 @@ class TwilioProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_sid,
|
||||
transport_kwargs={"stream_sid": stream_sid, "call_sid": call_sid},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ async def _persist_amd_result_if_present(
|
|||
@router.post("/twiml", include_in_schema=False)
|
||||
async def handle_twiml_webhook(
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
workflow_run_id: int,
|
||||
organization_id: int,
|
||||
request: Request,
|
||||
|
|
@ -79,7 +78,7 @@ async def handle_twiml_webhook(
|
|||
)
|
||||
|
||||
response_content = await provider.get_webhook_response(
|
||||
workflow_id, user_id, workflow_run_id
|
||||
workflow_id, organization_id, workflow_run_id
|
||||
)
|
||||
|
||||
return HTMLResponse(content=response_content, media_type="application/xml")
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ class VobizProvider(TelephonyProvider):
|
|||
return is_valid
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""
|
||||
Generate Vobiz XML response for starting a call session.
|
||||
|
|
@ -269,7 +269,7 @@ class VobizProvider(TelephonyProvider):
|
|||
|
||||
vobiz_xml = f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Response>
|
||||
<Stream bidirectional="true" keepCallAlive="true" contentType="audio/x-mulaw;rate=8000">{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{user_id}/{workflow_run_id}</Stream>
|
||||
<Stream bidirectional="true" keepCallAlive="true" contentType="audio/x-mulaw;rate=8000">{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}</Stream>
|
||||
</Response>"""
|
||||
return vobiz_xml
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ class VobizProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -394,7 +394,7 @@ class VobizProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_id,
|
||||
transport_kwargs={"stream_id": stream_id, "call_id": call_id},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ async def _verify_vobiz_callback(
|
|||
|
||||
@router.post("/vobiz-xml", include_in_schema=False)
|
||||
async def handle_vobiz_xml_webhook(
|
||||
workflow_id: int, user_id: int, workflow_run_id: int, organization_id: int
|
||||
workflow_id: int, workflow_run_id: int, organization_id: int
|
||||
):
|
||||
"""
|
||||
Handle initial webhook from Vobiz when call is answered.
|
||||
|
|
@ -65,7 +65,7 @@ async def handle_vobiz_xml_webhook(
|
|||
set_current_run_id(workflow_run_id)
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Vobiz XML webhook called - "
|
||||
f"workflow_id={workflow_id}, user_id={user_id}, org_id={organization_id}"
|
||||
f"workflow_id={workflow_id}, org_id={organization_id}"
|
||||
)
|
||||
|
||||
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
|
||||
|
|
@ -74,7 +74,7 @@ async def handle_vobiz_xml_webhook(
|
|||
logger.debug(f"[run {workflow_run_id}] Using provider: {provider.PROVIDER_NAME}")
|
||||
|
||||
response_content = await provider.get_webhook_response(
|
||||
workflow_id, user_id, workflow_run_id
|
||||
workflow_id, organization_id, workflow_run_id
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ class VonageProvider(TelephonyProvider):
|
|||
return False
|
||||
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
self, workflow_id: int, organization_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""
|
||||
Generate NCCO response for starting a call session.
|
||||
|
|
@ -222,7 +222,7 @@ class VonageProvider(TelephonyProvider):
|
|||
"endpoint": [
|
||||
{
|
||||
"type": "websocket",
|
||||
"uri": f"{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{user_id}/{workflow_run_id}",
|
||||
"uri": f"{wss_backend_endpoint}/api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}",
|
||||
"content-type": "audio/l16;rate=16000", # 16kHz Linear PCM
|
||||
"headers": {},
|
||||
}
|
||||
|
|
@ -323,7 +323,7 @@ class VonageProvider(TelephonyProvider):
|
|||
self,
|
||||
websocket: "WebSocket",
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
organization_id: int,
|
||||
workflow_run_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -338,14 +338,17 @@ class VonageProvider(TelephonyProvider):
|
|||
|
||||
try:
|
||||
# Get workflow run to extract call UUID
|
||||
workflow_run = await db_client.get_workflow_run(workflow_run_id)
|
||||
workflow_run = await db_client.get_workflow_run(
|
||||
workflow_run_id, organization_id=organization_id
|
||||
)
|
||||
if not workflow_run:
|
||||
logger.error(f"Workflow run {workflow_run_id} not found")
|
||||
await websocket.close(code=4404, reason="Workflow run not found")
|
||||
return
|
||||
|
||||
# Get workflow for organization info
|
||||
workflow = await db_client.get_workflow(workflow_id, user_id)
|
||||
workflow = await db_client.get_workflow(
|
||||
workflow_id, organization_id=organization_id
|
||||
)
|
||||
if not workflow:
|
||||
logger.error(f"Workflow {workflow_id} not found")
|
||||
await websocket.close(code=4404, reason="Workflow not found")
|
||||
|
|
@ -392,7 +395,7 @@ class VonageProvider(TelephonyProvider):
|
|||
provider_name=self.PROVIDER_NAME,
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=workflow_run_id,
|
||||
user_id=user_id,
|
||||
organization_id=organization_id,
|
||||
call_id=call_uuid,
|
||||
transport_kwargs={"call_uuid": call_uuid},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ provider registry — see ProviderSpec.router.
|
|||
"""
|
||||
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from loguru import logger
|
||||
|
|
@ -20,9 +19,8 @@ router = APIRouter()
|
|||
@router.get("/ncco", include_in_schema=False)
|
||||
async def handle_ncco_webhook(
|
||||
workflow_id: int,
|
||||
user_id: int,
|
||||
workflow_run_id: int,
|
||||
organization_id: Optional[int] = None,
|
||||
organization_id: int,
|
||||
):
|
||||
"""Handle NCCO (Nexmo Call Control Objects) webhook for Vonage.
|
||||
|
||||
|
|
@ -30,12 +28,10 @@ async def handle_ncco_webhook(
|
|||
"""
|
||||
|
||||
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
|
||||
provider = await get_telephony_provider_for_run(
|
||||
workflow_run, organization_id or user_id
|
||||
)
|
||||
provider = await get_telephony_provider_for_run(workflow_run, organization_id)
|
||||
|
||||
response_content = await provider.get_webhook_response(
|
||||
workflow_id, user_id, workflow_run_id
|
||||
workflow_id, organization_id, workflow_run_id
|
||||
)
|
||||
|
||||
return json.loads(response_content)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue