diff --git a/routes/helpers.py b/routes/helpers.py
deleted file mode 100644
index 1130537..0000000
--- a/routes/helpers.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import random, time
-import phonenumbers
-import hashlib
-import hmac
-import json
-import logging
-from datetime import datetime
-from config import YEASTAR_WEBHOOK_URL, YEASTAR_SECRET
-
-def generate_signature(body: str) -> str:
- signature = hmac.new(YEASTAR_SECRET.encode(), body.encode(), hashlib.sha256).hexdigest()
- return f"sha256={signature}"
-
-def to_e164(number):
- try:
- parsed = phonenumbers.parse(number, "US")
- return phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164)
- except Exception as e:
- logging.warning(f"Failed to normalize phone number {number}: {e}")
- return number
-
-def create_yeastar_payload(data):
- now_iso = datetime.now().astimezone().isoformat()
- message_id = str(int(datetime.utcnow().timestamp()))
- payload = {
- "data": {
- "event_type": "message.received",
- "payload": {
- "id": message_id,
- "from": {
- "phone_number": data["from"]
- },
- "to": [
- {"phone_number": num} for num in data["to"]
- ],
- "text": data["text"],
- "record_type": "message",
- "received_at": now_iso
- }
- }
- }
-
- media_urls = data.get("media_urls", [])
- if media_urls:
- payload["data"]["payload"].pop("text", None)
- payload["data"]["payload"]["media"] = [{"url": url} for url in media_urls]
-
- return payload
-
-def generate_message_id():
- return f"{random.randint(100000, 999999)}{int(time.time())}"
-
-def parse_bearer_token(auth_header):
- """
- Expect: Authorization: Bearer username|||password
- """
- if not auth_header.startswith("Bearer "):
- return None, None
- token = auth_header.split("Bearer ")[1].strip()
- parts = token.split("|||")
- if len(parts) == 2:
- return parts[0], parts[1]
- return None, None
-
-def build_soap_envelope(
- username, password, from_number, to_number,
- message_text, media_urls=None
-):
- media_urls = media_urls or []
- is_mms = len(media_urls) > 0
- soap_method = "sendMMS" if is_mms else "sendSMS"
-
- envelope = f"""
-
-
-
-
-
- {username}
- {password}
- {from_number}
- {to_number}
- {message_text}
-"""
-
- # Add media tags if MMS, max 3 allowed
- if is_mms:
- for i, url in enumerate(media_urls[:3]):
- envelope += f" {url}\n"
-
- envelope += f"""
-
-
-"""
-
- return envelope.strip()
-
diff --git a/routes/voipms.py b/routes/voipms.py
index a382917..83b1943 100644
--- a/routes/voipms.py
+++ b/routes/voipms.py
@@ -1,10 +1,11 @@
# routes/voipms.py
import json
+import hmac, hashlib
+import phonenumbers
from datetime import datetime
from flask import Blueprint, request, jsonify
from config import YEASTAR_WEBHOOK_URL, YEASTAR_SECRET, ENDPOINT_OBSCURITY
-from routes.helpers import to_e164, create_yeastar_payload, generate_signature
import requests
import logging
import uuid
@@ -84,3 +85,43 @@ def voipms_inbound():
except Exception as e:
logging.error(f"[{request_id}] Error in voipms_inbound: {e}", exc_info=True)
return jsonify({"error": "internal server error"}), 500
+
+def generate_signature(body: str) -> str:
+ signature = hmac.new(YEASTAR_SECRET.encode(), body.encode(), hashlib.sha256).hexdigest()
+ return f"sha256={signature}"
+
+def to_e164(number):
+ try:
+ parsed = phonenumbers.parse(number, "US")
+ return phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164)
+ except Exception as e:
+ logging.warning(f"Failed to normalize phone number {number}: {e}")
+ return number
+
+def create_yeastar_payload(data):
+ now_iso = datetime.now().astimezone().isoformat()
+ message_id = str(int(datetime.utcnow().timestamp()))
+ payload = {
+ "data": {
+ "event_type": "message.received",
+ "payload": {
+ "id": message_id,
+ "from": {
+ "phone_number": data["from"]
+ },
+ "to": [
+ {"phone_number": num} for num in data["to"]
+ ],
+ "text": data["text"],
+ "record_type": "message",
+ "received_at": now_iso
+ }
+ }
+ }
+
+ media_urls = data.get("media_urls", [])
+ if media_urls:
+ payload["data"]["payload"].pop("text", None)
+ payload["data"]["payload"]["media"] = [{"url": url} for url in media_urls]
+
+ return payload
diff --git a/routes/yeastar.py b/routes/yeastar.py
index c718d9d..4d87555 100644
--- a/routes/yeastar.py
+++ b/routes/yeastar.py
@@ -1,10 +1,10 @@
from flask import Blueprint, request, jsonify
+import random, time
import requests
import xml.etree.ElementTree as ET
from datetime import datetime
from config import VOIPMS_ENDPOINT, ENDPOINT_OBSCURITY
-from routes.helpers import generate_message_id, parse_bearer_token, build_soap_envelope
bp = Blueprint('yeastar', __name__)
@@ -118,4 +118,54 @@ def handle_yeastar_outbound():
"title": "Message Failed",
"detail": f"VOIP.ms returned status: {status or 'unknown'}"
}]
- }), 400
\ No newline at end of file
+ }), 400
+
+def generate_message_id():
+ return f"{random.randint(100000, 999999)}{int(time.time())}"
+
+def parse_bearer_token(auth_header):
+ """
+ Expect: Authorization: Bearer username|||password
+ """
+ if not auth_header.startswith("Bearer "):
+ return None, None
+ token = auth_header.split("Bearer ")[1].strip()
+ parts = token.split("|||")
+ if len(parts) == 2:
+ return parts[0], parts[1]
+ return None, None
+
+def build_soap_envelope(
+ username, password, from_number, to_number,
+ message_text, media_urls=None
+):
+ media_urls = media_urls or []
+ is_mms = len(media_urls) > 0
+ soap_method = "sendMMS" if is_mms else "sendSMS"
+
+ envelope = f"""
+
+
+
+
+
+ {username}
+ {password}
+ {from_number}
+ {to_number}
+ {message_text}
+"""
+
+ # Add media tags if MMS, max 3 allowed
+ if is_mms:
+ for i, url in enumerate(media_urls[:3]):
+ envelope += f" {url}\n"
+
+ envelope += f"""
+
+
+"""
+
+ return envelope.strip()
\ No newline at end of file
diff --git a/webhook-proxy.pyproj b/webhook-proxy.pyproj
index 6212a17..14ad029 100644
--- a/webhook-proxy.pyproj
+++ b/webhook-proxy.pyproj
@@ -27,7 +27,6 @@
-