mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-25 12:01:04 +02:00
feat: add vici dial controls from UI (#563)
* ViciDial Working * feat(telephony): add FreeSWITCH provider to upstream-PBX seam Generalize the upstream-PBX capture and control paths to dispatch by provider. FreeSWITCH bridges in with X-PBX-* headers and is driven over the Event Socket Library (uuid_kill / uuid_transfer) by the channel UUID, alongside the existing VICIdial ra_call_control path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * add vici specific configs * feat(telephony): env-based VICIdial config + address3 post-call routing Move VICIdial agent/non-agent API and FreeSWITCH ESL connection settings out of hardcoded POC values into environment variables so the same image works against a PBX on another server. Add VICIdial update_lead forwarding: X-VICI-UPDATE-LEAD_* extracted variables are mapped to lead columns and pushed via the non-agent API before a transfer, with reserved API-control params dropped. Add hardcoded address3 disposition routing (Y/N -> in-group transfer, else hang up) and a synchronous final variable extraction so the transfer path sees the freshest conversation state. Skip upstream_pbx capture on non-PJSIP channels to avoid Asterisk 500s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: run formatter * feat: make vici configurable from UI * chore: clean up PR * fix: incorporate review comments * chore: incorporate review comments * chore: generate client * chore: incporporate review comments * chore: incorporate review comments --------- Co-authored-by: Dograh POC <payment@dograh.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2f7b47a1b4
commit
d8cd34e8d2
51 changed files with 2886 additions and 102 deletions
80
api/tests/telephony/test_external_pbx_configuration.py
Normal file
80
api/tests/telephony/test_external_pbx_configuration.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
from api.routes import organization
|
||||
from api.services import tool_management
|
||||
|
||||
|
||||
def _credentials(password: str = "agent-secret") -> dict:
|
||||
return {
|
||||
"ari_endpoint": "https://asterisk.example.com",
|
||||
"app_name": "dograh",
|
||||
"app_password": "ari-secret",
|
||||
"external_pbx": {
|
||||
"type": "vicidial",
|
||||
"agent_api": {
|
||||
"url": "https://vici.example.com/agc/api.php",
|
||||
"username": "agent-user",
|
||||
"password": password,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_nested_external_pbx_secrets_are_masked_without_mutating_source():
|
||||
credentials = _credentials()
|
||||
|
||||
masked = organization._mask_sensitive("ari", credentials)
|
||||
|
||||
assert masked["app_password"] != "ari-secret"
|
||||
assert masked["external_pbx"]["agent_api"]["password"] != "agent-secret"
|
||||
assert credentials["external_pbx"]["agent_api"]["password"] == "agent-secret"
|
||||
|
||||
|
||||
def test_nested_masked_external_pbx_secrets_are_restored_on_update():
|
||||
existing = _credentials()
|
||||
request = organization._mask_sensitive("ari", existing)
|
||||
|
||||
organization.preserve_masked_fields("ari", request, existing)
|
||||
|
||||
assert request["app_password"] == "ari-secret"
|
||||
assert request["external_pbx"]["agent_api"]["password"] == "agent-secret"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disabled_feature_preserves_existing_tool_mapping(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
tool_management,
|
||||
"external_pbx_integrations_enabled",
|
||||
AsyncMock(return_value=False),
|
||||
)
|
||||
definition = {
|
||||
"type": "transfer_call",
|
||||
"config": {
|
||||
"destination_source": "context_mapping",
|
||||
"context_mapping": {
|
||||
"context_path": "qualified",
|
||||
"routes": [{"context_value": "yes", "destination": "sales"}],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
await tool_management.validate_external_pbx_tool_definition(
|
||||
definition,
|
||||
organization_id=7,
|
||||
existing_definition=definition,
|
||||
)
|
||||
|
||||
changed = {
|
||||
"type": "transfer_call",
|
||||
"config": {"destination_source": "static", "destination": "+15555550100"},
|
||||
}
|
||||
with pytest.raises(tool_management.ToolManagementError) as exc_info:
|
||||
await tool_management.validate_external_pbx_tool_definition(
|
||||
changed,
|
||||
organization_id=7,
|
||||
existing_definition=definition,
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 403
|
||||
Loading…
Add table
Add a link
Reference in a new issue