release: v2.8.19

This commit is contained in:
Christian 2026-09-25 15:25:13 +02:00
parent 20e6dc14b6
commit 49bc74e199
4 changed files with 80 additions and 9 deletions

View File

@ -1 +1 @@
2.8.18
2.8.19

View File

@ -270,6 +270,8 @@ async def yealink_established(
local: Optional[str] = Query(None),
active_user: Optional[str] = Query(None),
called_number: Optional[str] = Query(None),
display_remote: Optional[str] = Query(None),
caller_id: Optional[str] = Query(None),
token: Optional[str] = Query(None),
):
"""Yealink Action URL: Established"""
@ -306,6 +308,8 @@ async def yealink_established(
caller_value = _sanitize(caller) or _sanitize(remote)
callee_value = _sanitize(callee)
called_number_value = _sanitize(called_number)
display_remote_value = _sanitize(display_remote)
caller_id_value = _sanitize(caller_id)
local_extension = extract_extension(local_value) or local_value
@ -325,6 +329,8 @@ async def yealink_established(
] if direction == "outbound" else [
caller_value,
_sanitize(remote),
display_remote_value,
caller_id_value,
callee_value,
called_number_value,
]
@ -335,18 +341,16 @@ async def yealink_established(
ekstern_raw = candidate
break
if not ekstern_raw:
for candidate in candidates:
if candidate:
ekstern_raw = candidate
break
ekstern_normalized = normalize_external_number(ekstern_raw)
ekstern_e164 = normalize_e164(ekstern_normalized or ekstern_raw)
ekstern_value = ekstern_normalized or ((ekstern_raw or "").strip() or None)
# A SIP URI such as sip:206@... is the forwarding extension, not the
# customer. Keep it in raw_payload for diagnostics, but never display or
# match it as an external caller number.
ekstern_value = ekstern_normalized or ekstern_e164
user_ids = TelefoniService.find_user_by_extension(local_extension)
kontakt = TelefoniService.find_contact_by_phone(ekstern_raw)
kontakt = TelefoniService.find_contact_by_phone(ekstern_value)
kontakt_id = kontakt.get("id") if kontakt else None
# Get extended contact details if we found a contact
@ -363,6 +367,8 @@ async def yealink_established(
"local": local_value,
"active_user": active_user,
"called_number": called_number_value,
"display_remote": display_remote_value,
"caller_id": caller_id_value,
"direction": direction,
"client_ip": _get_client_ip(request),
"user_agent": request.headers.get("user-agent"),

View File

@ -2643,7 +2643,7 @@ function buildYealinkActionUrls() {
const base = baseRaw.replace(/\/$/, '');
const tokenPart = token ? `token=${encodeURIComponent(token)}&` : '';
estEl.value = `${base}/api/v1/telefoni/established?${tokenPart}callid=$call_id&remote=$remote&local=$local&active_user=$active_user&called_number=$calledNumber`;
estEl.value = `${base}/api/v1/telefoni/established?${tokenPart}callid=$call_id&remote=$remote&display_remote=$display_remote&caller_id=$callerID&local=$local&active_user=$active_user&called_number=$calledNumber`;
termEl.value = `${base}/api/v1/telefoni/terminated?${tokenPart}callid=$call_id&duration=$call_duration`;
}

View File

@ -130,6 +130,71 @@ def test_reused_callids_only_conflict_while_the_call_is_active():
assert "ux_telefoni_opkald_active_callid" in migration
def test_forwarded_call_uses_yealink_displayed_caller_number(monkeypatch):
captured = {}
monkeypatch.setattr(telefoni_router, "_validate_yealink_request", lambda *_: None)
monkeypatch.setattr(TelefoniService, "find_user_by_extension", staticmethod(lambda _extension: []))
monkeypatch.setattr(TelefoniService, "find_contact_by_phone", staticmethod(lambda _number: None))
monkeypatch.setattr(
TelefoniService,
"upsert_call",
staticmethod(lambda **kwargs: captured.update(kwargs) or {"id": 1}),
)
monkeypatch.setattr(telefoni_router, "log_system_event", lambda **_kwargs: None)
request = Request({"type": "http", "method": "GET", "path": "/", "headers": [], "client": ("127.0.0.1", 8001)})
asyncio.run(telefoni_router.yealink_established(
request,
callid="116",
call_id=None,
caller=None,
callee=None,
remote="sip:206@pbx.sipserver.dk",
local="sip:210_99773@pbx.sipserver.dk",
active_user=None,
called_number=None,
display_remote="+45 49 13 27 73",
caller_id=None,
token=None,
))
assert captured["direction"] == "inbound"
assert captured["ekstern_nummer"] == "+4549132773"
def test_forwarded_call_does_not_store_forwarding_sip_uri(monkeypatch):
captured = {}
monkeypatch.setattr(telefoni_router, "_validate_yealink_request", lambda *_: None)
monkeypatch.setattr(TelefoniService, "find_user_by_extension", staticmethod(lambda _extension: []))
monkeypatch.setattr(TelefoniService, "find_contact_by_phone", staticmethod(lambda _number: None))
monkeypatch.setattr(
TelefoniService,
"upsert_call",
staticmethod(lambda **kwargs: captured.update(kwargs) or {"id": 1}),
)
monkeypatch.setattr(telefoni_router, "log_system_event", lambda **_kwargs: None)
request = Request({"type": "http", "method": "GET", "path": "/", "headers": [], "client": ("127.0.0.1", 8001)})
asyncio.run(telefoni_router.yealink_established(
request,
callid="117",
call_id=None,
caller=None,
callee=None,
remote="sip:206@pbx.sipserver.dk",
local="sip:210_99773@pbx.sipserver.dk",
active_user=None,
called_number=None,
display_remote=None,
caller_id=None,
token=None,
))
assert captured["ekstern_nummer"] is None
def test_callid_recovery_uses_system_log_without_overwriting_existing_current_calls():
migration = Path("migrations/1047_telefoni_reused_callids.sql").read_text(encoding="utf-8")