bmc_hub/app/modules/telefoni/backend/utils.py
Christian bc504b9257 feat: Add subscription management functionality and AnyDesk API integration
- Implemented subscription creation, updating, and rendering in script_9.js.
- Added functions for handling subscription line items, product selection, and total calculations.
- Integrated AnyDesk API for session management in test_anydesk.py.
- Created REST client test requests for API endpoints in api.http.
- Developed a script to check ESET machine status and save details in tmp_check_eset_machine.py.
2026-03-30 07:50:15 +02:00

118 lines
2.9 KiB
Python

import ipaddress
import re
from typing import Optional
def digits_only(value: Optional[str]) -> str:
if not value:
return ""
return re.sub(r"\D+", "", value)
def normalize_e164(number: Optional[str]) -> Optional[str]:
if not number:
return None
raw = number.strip().replace(" ", "").replace("-", "")
if not raw:
return None
if raw.startswith("+"):
n = "+" + digits_only(raw)
return n if len(n) >= 9 else None
if raw.startswith("0045"):
rest = digits_only(raw[4:])
return "+45" + rest if len(rest) == 8 else ("+" + digits_only(raw) if len(digits_only(raw)) >= 9 else None)
d = digits_only(raw)
if len(d) == 8:
return "+45" + d
if d.startswith("45") and len(d) == 10:
return "+" + d
# Generic international (best-effort)
if len(d) >= 9:
return "+" + d
return None
def phone_suffix_8(number: Optional[str]) -> Optional[str]:
d = digits_only(number)
if len(d) < 8:
return None
return d[-8:]
def phone_digits_full(number: Optional[str]) -> Optional[str]:
"""Return full digit string strip of any +45/0045 prefix for Danish numbers."""
if not number:
return None
d = digits_only(number)
if not d:
return None
# Strip leading 0045 or 45 prefix from 10-digit Danish numbers
if d.startswith("0045") and len(d) == 12:
return d[4:]
if d.startswith("45") and len(d) == 10:
return d[2:]
return d
def is_outbound_call(caller: Optional[str], local_extension: Optional[str]) -> bool:
caller_d = digits_only(caller)
local_d = digits_only(local_extension)
if not caller_d or not local_d:
return False
return caller_d.endswith(local_d)
def extract_extension(local_value: Optional[str]) -> Optional[str]:
if not local_value:
return None
raw = local_value.strip()
if not raw:
return None
if raw.isdigit():
return raw
# Common SIP format: sip:204_99773@pbx.sipserver.dk -> 204
sip_match = re.search(r"sip:([0-9]+)", raw, flags=re.IGNORECASE)
if sip_match:
return sip_match.group(1)
# Fallback: first digit run (at least 2 chars)
generic = re.search(r"([0-9]{2,})", raw)
if generic:
return generic.group(1)
return None
def ip_in_whitelist(client_ip: str, whitelist_csv: str) -> bool:
if not client_ip or not whitelist_csv:
return False
try:
ip_obj = ipaddress.ip_address(client_ip)
except ValueError:
return False
for entry in [e.strip() for e in whitelist_csv.split(",") if e.strip()]:
try:
if "/" in entry:
net = ipaddress.ip_network(entry, strict=False)
if ip_obj in net:
return True
else:
if ip_obj == ipaddress.ip_address(entry):
return True
except ValueError:
continue
return False