working api compltely

This commit is contained in:
2025-09-23 22:40:16 -04:00
parent f2faced238
commit f6e22bb975
21 changed files with 249 additions and 53 deletions

10
.env Normal file
View File

@@ -0,0 +1,10 @@
# --- VoIP.ms API Credentials ---
# Find these in your VoIP.ms customer portal under Main Menu > SOAP and REST/JSON API
VOIPMS_API_USERNAME="eddwinn@gmail.com"
VOIPMS_API_PASSWORD="!Gofionago123catdog"
# --- Target DID and Routing Destinations ---
TARGET_DID="5084268800"
TARGET_SIP_ACCOUNT="407323_auburnoil@washington2.voip.ms" # e.g., 123456_myhome@newyork1.voip.ms
TARGET_CELLPHONE_1="7743342638" # Use E.164 format (country code + number)
TARGET_CELLPHONE_2="9143306100" # Use E.164 format

0
.gitignore vendored Normal file
View File

View File

@@ -6,9 +6,11 @@ ENV PYTHONUNBUFFERED=1
ENV MODE="DEVELOPMENT"
WORKDIR /app
ENV PYTHONPATH=/app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,22 +0,0 @@
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
# Load settings from the .env file
model_config = SettingsConfigDict(env_file="../.env", env_file_encoding='utf-8')
# VoIP.ms Credentials
voipms_api_username: str
voipms_api_password: str
# Target DID and Destinations
target_did: str
target_sip_account: str
target_cellphone_1: str
target_cellphone_2: str
# VoIP.ms API endpoint
voipms_api_url: str = "https://voip.ms/api/v1/rest.php"
# Create a single instance of the settings to be used throughout the app
settings = Settings()

View File

@@ -1,6 +1,10 @@
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from settings_dev import settings
import requests
from fastapi import FastAPI, HTTPException, status
from .config import settings
from .voipms_client import update_did_routing
from .voipms_client import update_did_routing, get_forwardings
from .database import Session
from .models import Call
@@ -9,9 +13,33 @@ app = FastAPI(
description="An API to manage routing for a VoIP.ms DID.",
version="1.0.0",
)
@app.get("/test/forwardings")
def test_get_forwardings():
try:
result = get_forwardings(phone_number=settings.target_cellphone_1)
return {
"message": f"Forwarding entry for {settings.target_cellphone_1}",
"voipms_response": result
}
except HTTPException as e:
raise e
@app.get("/test/did")
def test_did_info():
params = {
"api_username": settings.voipms_api_username,
"api_password": settings.voipms_api_password,
"method": "getDIDsInfo", # Correct: plural "DIDs"
"did": settings.target_did, # Filters to one DID
}
try:
response = requests.get(settings.voipms_api_url, params=params)
print(f"Test Request URL: {response.request.url}")
print(f"Test Response: {response.json()}")
return response.json()
except requests.exceptions.RequestException as e:
return {"error": f"Failed to connect to VoIP.ms API: {str(e)}", "params": params}
except Exception as e:
return {"error": f"Unexpected error: {str(e)}", "params": params}
@app.get("/", tags=["General"])
def read_root():
"""A simple root endpoint to confirm the API is running."""
@@ -23,10 +51,12 @@ def route_to_sip_account():
"""
Routes the target DID to the pre-configured SIP account.
"""
routing_string = f"sip:{settings.target_sip_account}"
try:
# Use sub-account ID from TARGET_SIP_ACCOUNT
sip_account_id = settings.target_sip_account.split('@')[0] # Extract '407323_auburnoil'
routing_string = f"account:{sip_account_id}" # e.g., 'account:407323_auburnoil'
result = update_did_routing(did=settings.target_did, routing=routing_string)
target_phone = routing_string.split(':')[1]
target_phone = sip_account_id
db = Session()
db.add(Call(current_phone=target_phone))
db.commit()
@@ -36,7 +66,6 @@ def route_to_sip_account():
"voipms_response": result
}
except HTTPException as e:
# Re-raise the exception to let FastAPI handle the response
raise e
@@ -45,10 +74,18 @@ def route_to_cellphone_1():
"""
Routes the target DID to the pre-configured Cellphone #1.
"""
routing_string = f"fwd:{settings.target_cellphone_1}"
try:
# Get the forwarding entry for the phone number
forwarding = get_forwardings(phone_number=settings.target_cellphone_1)
forwarding_id = forwarding.get("forwarding") # e.g., '998692'
if not forwarding_id:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"No forwarding ID found for phone number {settings.target_cellphone_1}"
)
routing_string = f"fwd:{forwarding_id}" # e.g., 'fwd:998692'
result = update_did_routing(did=settings.target_did, routing=routing_string)
target_phone = routing_string.split(':')[1]
target_phone = settings.target_cellphone_1
db = Session()
db.add(Call(current_phone=target_phone))
db.commit()
@@ -60,16 +97,23 @@ def route_to_cellphone_1():
except HTTPException as e:
raise e
@app.post("/route/cellphone2", status_code=status.HTTP_200_OK, tags=["DID Routing"])
def route_to_cellphone_2():
"""
Routes the target DID to the pre-configured Cellphone #2.
"""
routing_string = f"fwd:{settings.target_cellphone_2}"
try:
# Get the forwarding entry for the phone number
forwarding = get_forwardings(phone_number=settings.target_cellphone_2)
forwarding_id = forwarding.get("forwarding") # e.g., ID for 9143306100
if not forwarding_id:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"No forwarding ID found for phone number {settings.target_cellphone_2}"
)
routing_string = f"fwd:{forwarding_id}" # e.g., 'fwd:<ID>'
result = update_did_routing(did=settings.target_did, routing=routing_string)
target_phone = routing_string.split(':')[1]
target_phone = settings.target_cellphone_2
db = Session()
db.add(Call(current_phone=target_phone))
db.commit()
@@ -79,4 +123,4 @@ def route_to_cellphone_2():
"voipms_response": result
}
except HTTPException as e:
raise e
raise e

View File

@@ -1,7 +1,53 @@
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from settings_dev import settings
import requests
from fastapi import HTTPException, status
from .config import settings
def get_did_info(did: str):
"""
Calls the VoIP.ms API to get DID information.
Args:
did (str): The phone number (DID) to query.
Raises:
HTTPException: If the API call fails or returns an error.
Returns:
dict: The JSON response from the VoIP.ms API on success.
"""
params = {
"api_username": settings.voipms_api_username,
"api_password": settings.voipms_api_password,
"method": "getDIDInfo",
"did": did,
}
try:
response = requests.get(settings.voipms_api_url, params=params)
response.raise_for_status()
data = response.json()
if data.get("status") != "success":
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"VoIP.ms API Error: {data.get('status')}. Full response: {data}. Request params: {params}"
)
return data
except requests.exceptions.RequestException as e:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Failed to connect to VoIP.ms API: {e}"
)
except Exception as e:
if isinstance(e, HTTPException):
raise e
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred: {e}"
)
def update_did_routing(did: str, routing: str):
"""
@@ -20,37 +66,84 @@ def update_did_routing(did: str, routing: str):
params = {
"api_username": settings.voipms_api_username,
"api_password": settings.voipms_api_password,
"method": "setDIDInfo",
"method": "setDIDRouting", # Correct method for routing updates
"did": did,
"routing": routing,
"routing": routing, # e.g., 'fwd:7743342638'
"pop": "75", # Match the DID's current POP (from getDIDsInfo)
}
try:
response = requests.get(settings.voipms_api_url, params=params)
response.raise_for_status() # Raises an HTTPError for bad responses (4xx or 5xx)
print(f"Request URL: {response.request.url}") # Debug
print(f"Request Params: {params}") # Debug
response.raise_for_status()
data = response.json()
print(f"VoIP.ms API Response: {data}") # Debug
# VoIP.ms API has its own status field in the JSON response
if data.get("status") != "success":
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"VoIP.ms API Error: {data.get('status')}"
detail=f"VoIP.ms API Error: {data.get('status')} - Full response: {data}"
)
return data
except requests.exceptions.RequestException as e:
# Handle network errors, timeouts, etc.
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Failed to connect to VoIP.ms API: {e}"
detail=f"Failed to connect to VoIP.ms API: {e} - Request params: {params}"
)
except Exception as e:
# Catch any other exceptions, including the ones we raised manually
if isinstance(e, HTTPException):
raise e # Re-raise if it's already an HTTPException
raise e
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred: {e}"
detail=f"An unexpected error occurred: {e} - Request params: {params}"
)
def get_forwardings(phone_number: str = None):
"""
Retrieves call forwarding entries from VoIP.ms.
Args:
phone_number (str, optional): Filter by phone number (e.g., '7743342638').
Returns:
dict: The JSON response from the VoIP.ms API, including forwarding IDs.
"""
params = {
"api_username": settings.voipms_api_username,
"api_password": settings.voipms_api_password,
"method": "getForwardings",
}
try:
response = requests.get(settings.voipms_api_url, params=params)
print(f"Get Forwardings Request URL: {response.request.url}")
print(f"Get Forwardings Response: {response.json()}")
response.raise_for_status()
data = response.json()
if data.get("status") != "success":
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"VoIP.ms API Error: {data.get('status')} - Full response: {data}"
)
# Filter by phone_number if provided
if phone_number and "forwardings" in data:
for forwarding in data["forwardings"]:
if forwarding.get("phone_number") == phone_number:
return forwarding
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"No forwarding entry found for phone number {phone_number}"
)
return data
except requests.exceptions.RequestException as e:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Failed to connect to VoIP.ms API: {e} - Request params: {params}"
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred: {e} - Request params: {params}"
)

View File

@@ -22,5 +22,5 @@ def load_config(mode=os.environ.get('MODE')):
pass
except ImportError:
from settings_local import ApplicationConfig
from settings_dev import ApplicationConfig
return ApplicationConfig

View File

@@ -1,4 +1,7 @@
fastapi
uvicorn[standard]
pydantic-settings
requests
python-dotenv
requests
sqlalchemy
psycopg2-binary

View File

@@ -1,5 +1,11 @@
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
class ApplicationConfig:
"""
Basic Configuration for a generic User
@@ -33,3 +39,20 @@ class ApplicationConfig:
# # Authorize.net credentials (Sandbox Test Credentials)
# API_LOGIN_ID = '5KP3u95bQpv'
# TRANSACTION_KEY = '346HZ32z3fP4hTG2'
# VoIP.ms Credentials and Settings
voipms_api_username = os.environ.get('VOIPMS_API_USERNAME')
voipms_api_password = os.environ.get('VOIPMS_API_PASSWORD')
# Target DID and Destinations
target_did = os.environ.get('TARGET_DID')
target_sip_account = os.environ.get('TARGET_SIP_ACCOUNT')
target_cellphone_1 = os.environ.get('TARGET_CELLPHONE_1')
target_cellphone_2 = os.environ.get('TARGET_CELLPHONE_2')
# VoIP.ms API endpoint
voipms_api_url = os.environ.get('VOIPMS_API_URL', "https://voip.ms/api/v1/rest.php")
# Create a single instance of the settings to be used throughout the app
settings = ApplicationConfig()

View File

@@ -1,5 +1,11 @@
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
class ApplicationConfig:
"""
Basic Configuration for a generic User
@@ -26,5 +32,20 @@ class ApplicationConfig:
"http://192.168.1.204:9614",
"http://192.168.1.204:9612",
"http://192.168.1.204:9611",
]
]
# VoIP.ms Credentials and Settings
voipms_api_username = os.environ.get('VOIPMS_API_USERNAME')
voipms_api_password = os.environ.get('VOIPMS_API_PASSWORD')
# Target DID and Destinations
target_did = os.environ.get('TARGET_DID')
target_sip_account = os.environ.get('TARGET_SIP_ACCOUNT')
target_cellphone_1 = os.environ.get('TARGET_CELLPHONE_1')
target_cellphone_2 = os.environ.get('TARGET_CELLPHONE_2')
# VoIP.ms API endpoint
voipms_api_url = os.environ.get('VOIPMS_API_URL', "https://voip.ms/api/v1/rest.php")
# Create a single instance of the settings to be used throughout the app
settings = ApplicationConfig()

View File

@@ -1,3 +1,10 @@
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
class ApplicationConfig:
"""
Basic Configuration for a generic User
@@ -19,4 +26,19 @@ class ApplicationConfig:
origins = [
"https://oil.edwineames.com",
"https://apiauto.edwineames.com",
]
]
# VoIP.ms Credentials and Settings
voipms_api_username = os.environ.get('VOIPMS_API_USERNAME')
voipms_api_password = os.environ.get('VOIPMS_API_PASSWORD')
# Target DID and Destinations
target_did = os.environ.get('TARGET_DID')
target_sip_account = os.environ.get('TARGET_SIP_ACCOUNT')
target_cellphone_1 = os.environ.get('TARGET_CELLPHONE_1')
target_cellphone_2 = os.environ.get('TARGET_CELLPHONE_2')
# VoIP.ms API endpoint
voipms_api_url = os.environ.get('VOIPMS_API_URL', "https://voip.ms/api/v1/rest.php")
# Create a single instance of the settings to be used throughout the app
settings = ApplicationConfig()