You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

354 lines
14 KiB

  1. import json
  2. import subprocess
  3. import logging
  4. import ipaddress
  5. #import api_utils.carddav_util as carddav_util
  6. #from .api_utils import carddav_util
  7. from enum import Enum
  8. from typing import Any, Dict, List, Optional
  9. # import wave
  10. import os
  11. import shutil
  12. from pathlib import Path
  13. from tempfile import NamedTemporaryFile
  14. from typing import Callable
  15. import base64
  16. from datetime import datetime, timedelta
  17. from api_utils import api_utils, coerce_methods
  18. from collections import OrderedDict
  19. from pydantic import BaseModel, Field
  20. from fastapi import Depends, FastAPI, HTTPException, File, UploadFile
  21. from fastapi.encoders import jsonable_encoder
  22. from fastapi.openapi.docs import get_swagger_ui_html
  23. from fastapi.openapi.utils import get_openapi
  24. from starlette.status import HTTP_403_FORBIDDEN
  25. from starlette.responses import RedirectResponse, Response, JSONResponse
  26. from starlette.requests import Request
  27. from starlette.middleware.cors import CORSMiddleware
  28. from starlette.responses import FileResponse
  29. from starlette.types import ASGIApp, Message, Receive, Scope, Send
  30. from models.cellular_hardware import cellularHardware
  31. from models.cellular_hardwares import cellularHardwares
  32. from models.call import call, post_call
  33. from models.calls import calls
  34. from models.httpresponse import httpResponse400, httpResponse200, httpResponse500
  35. from fastapi_login import LoginManager
  36. from core.security import manager, NotAuthenticatedException
  37. from routes import auth as _auth
  38. auth_router = _auth.router
  39. from routes import user as _user
  40. user_router = _user.router
  41. #from routes.posts import router as posts_router
  42. from routes import majornet as _majornet
  43. majornet_router = _majornet.router
  44. from routes import presence as _presence
  45. presence_router = _presence.router
  46. from routes import contacts as _contacts
  47. contacts_router = _contacts.router
  48. from routes import reslevis as _reslevis
  49. reslevis_router = _reslevis.router
  50. #security
  51. from fastapi import FastAPI, Security
  52. from fastapi.security import OAuth2AuthorizationCodeBearer
  53. AUTH_URL = "https://192.168.1.3:10002/realms/API.Server.local/protocol/openid-connect/auth"
  54. TOKEN_URL = "https://192.168.1.3:10002/realms/API.Server.local/protocol/openid-connect/token"
  55. oauth2 = OAuth2AuthorizationCodeBearer(
  56. authorizationUrl=AUTH_URL,
  57. tokenUrl=TOKEN_URL,
  58. scopes={"items:read": "Read items", "items:write": "Write items"},
  59. )
  60. log = logging.getLogger(__name__) # pylint: disable=invalid-name
  61. DEBUG = True
  62. app = FastAPI(title="MajorNet API", redoc_url=None, docs_url=None, openapi_url=None)
  63. ####DEV
  64. ##app = FastAPI(title=PROJECT_NAME)
  65. app.debug = True
  66. logging.basicConfig(filename='/tmp/app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s')
  67. logging.warning('This will /tmp/app.log')
  68. ALLOWED_HOSTS = ["*"]
  69. app.add_middleware(
  70. CORSMiddleware,
  71. allow_origins=ALLOWED_HOSTS,
  72. allow_credentials=True,
  73. allow_methods=["*"],
  74. allow_headers=["*"],
  75. )
  76. @app.exception_handler(NotAuthenticatedException)
  77. def auth_exception_handler(request: Request, exc: NotAuthenticatedException):
  78. """
  79. Redirect the user to the login page if not logged in
  80. """
  81. return RedirectResponse(url='/login')
  82. app.include_router(auth_router)
  83. app.include_router(user_router)
  84. #app.include_router(posts_router)
  85. app.include_router(presence_router)
  86. app.include_router(majornet_router)
  87. app.include_router(contacts_router)
  88. app.include_router(reslevis_router, prefix="/reslevis", tags=["reslevis"])
  89. @app.get("/")
  90. async def root():
  91. #return {"url": "/docs"}
  92. return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")
  93. @app.get("/openapi.json/", tags=["Documentation"])
  94. async def get_open_api_endpoint():
  95. #async def get_open_api_endpoint(current_user: User = Depends(get_current_active_user)):
  96. return JSONResponse(get_openapi(title="MajorNet APIs", version="1.0", routes=app.routes))
  97. @app.get("/docs/", tags=["Documentation"])
  98. #async def get_documentation(current_user: User = Depends(get_current_active_user)):
  99. async def get_documentation():
  100. if DEBUG: print("SONO IN /DOCS")
  101. return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")
  102. @app.post("/majortel/call/", tags=["Majortel"])
  103. async def route_call(active_user=Depends(manager),callerNumber=None, calledNumber=None):
  104. try:
  105. if DEBUG: print("Entro nel TRY")
  106. # Check if the callerNumber sent is an ip address and retrieve the associated number
  107. ipaddress.ip_address(callerNumber)
  108. callerNumberRetrieved = os.popen('asterisk -rx "sip show peers" | grep ' + callerNumber).read()
  109. callerNumberRetrieved = callerNumberRetrieved.split("/")
  110. callerNumber = callerNumberRetrieved[0]
  111. except:
  112. if DEBUG: print("EXCEPT")
  113. mode = "callFromTo"
  114. from_ = callerNumber
  115. to_ = calledNumber
  116. if DEBUG: print("DATI ARRIVATI: ")
  117. if DEBUG: print(callerNumber)
  118. if DEBUG: print(calledNumber)
  119. subprocess.Popen(['perl', '/usr/local/bin/ast/voice.pl', mode, from_, to_], stdout=subprocess.PIPE)
  120. return
  121. @app.post("/majortel/ring/", tags=["Majortel"])
  122. async def route_ring(active_user=Depends(manager),calledNumber=None, calledId=None, ringTime=None):
  123. try:
  124. if DEBUG: print("Entro nel TRY")
  125. # Check if the callerNumber sent is an ip address and retrieve the associated number
  126. ipaddress.ip_address(calledNumber)
  127. calledNumberRetrieved = os.popen('asterisk -rx "sip show peers" | grep ' + calledNumber).read()
  128. calledNumberRetrieved = calledNumberRetrieved.split("/")
  129. calledNumber = calledNumberRetrieved[0]
  130. except:
  131. if DEBUG: print("EXCEPT")
  132. mode = "ringAlert"
  133. to_ = calledNumber
  134. calledId_ = calledId
  135. ringTime_ = ringTime
  136. if DEBUG: print("DATI ARRIVATI: ")
  137. if DEBUG: print(calledNumber)
  138. if DEBUG: print(calledId)
  139. if DEBUG: print(ringTime)
  140. subprocess.Popen(['perl', '/usr/local/bin/ast/voice.pl', mode, to_, calledId_, ringTime_], stdout=subprocess.PIPE)
  141. return
  142. @app.get("/majortel/hardware/", response_model=cellularHardwares, tags=["Majortel"])
  143. #async def majortel_hardware_get(current_user: User = Depends(get_current_active_user)):
  144. async def majortel_hardware_get():
  145. gsm_temp_list = "GSM span1: Provisioned, Up, Active"
  146. response = {"CellularHardwares": []}
  147. hardware_dict = {}
  148. myCmd = os.popen('asterisk -rx "gsm show spans"').read()
  149. myCmd = myCmd.split("\n")
  150. # cancello l'ultimo item della lista poichè, risultando vuoto dopo lo split,
  151. # genera errore "index out of range" nei successivi accessi alla lista
  152. if DEBUG: print("spans: ")
  153. if DEBUG: print(myCmd)
  154. myCmd = os.popen('asterisk -rx "dongle show devices"').read()
  155. myCmd = myCmd.split("\n")
  156. # cancello il primo item della lista poichè contiene la legenda
  157. del myCmd[0]
  158. del myCmd[-1]
  159. # costruisco la response
  160. for device in myCmd:
  161. device = device.split()
  162. hardware_id = device[0]
  163. current_device = os.popen('asterisk -rx "dongle show device state ' + hardware_id + '"').read()
  164. current_device = current_device.split("\n")
  165. # cancello il primo e gli ultimi item della lista poichè, risultando vuoti dopo lo split,
  166. # generano errore "index out of range" nei successivi accessi alla lista
  167. del current_device[0]
  168. del current_device[-1]
  169. del current_device[-1]
  170. # costruisco un dizionario a partire dall'output della system call
  171. for row in current_device:
  172. row = row.split(":")
  173. row[0] = row[0].strip()
  174. row[1] = row[1].strip()
  175. hardware_dict[row[0]] = row[1]
  176. hardware_id = hardware_dict["Device"]
  177. status = hardware_dict["State"]
  178. signal = hardware_dict["RSSI"]
  179. signal = int(signal[0:2])
  180. operator = hardware_dict["Provider Name"]
  181. device_obj = {"id": hardware_id, "description": "description", "status": status, "signal_level": signal,
  182. "registered_number": "To Do", "operator": operator}
  183. response["CellularHardwares"].append(device_obj)
  184. return response
  185. @app.get("/majortel/hardware/{item_id}", response_model=cellularHardware, tags=["Majortel"], responses={400: {"model": httpResponse400}})
  186. #async def majortel_hardware_id_get(item_id: str, current_user: User = Depends(get_current_active_user)):
  187. async def majortel_hardware_id_get(item_id: str,active_user=Depends(manager)):
  188. hardware_response = {}
  189. hardware_dict = {}
  190. current_device = os.popen('asterisk -rx "dongle show device state ' + item_id + '"').read()
  191. current_device = current_device.split("\n")
  192. # cancello il primo e gli ultimi item della lista poichè, risultando vuoti dopo lo split,
  193. # generano errore "index out of range" nei successivi accessi alla lista
  194. del current_device[0]
  195. if (current_device[0]):
  196. del current_device[-1]
  197. del current_device[-1]
  198. # costruisco un dizionario a partire dall'output della system call
  199. for row in current_device:
  200. row = row.split(":")
  201. row[0] = row[0].strip()
  202. row[1] = row[1].strip()
  203. hardware_dict[row[0]] = row[1]
  204. hardware_id = hardware_dict["Device"]
  205. status = hardware_dict["State"]
  206. signal = hardware_dict["RSSI"]
  207. signal = int(signal[0:2])
  208. operator = hardware_dict["Provider Name"]
  209. hardware_response = {"id": hardware_id, "description": "description", "status": status, "signal_level": signal,
  210. "registered_number": "To Do", "operator": operator}
  211. return hardware_response
  212. else:
  213. return JSONResponse(status_code=404, content={"message": "Device not found"})
  214. @app.get("/majortel/calls/", response_model=calls, tags=["Majortel"])
  215. #async def majortel_calls_get(current_user: User = Depends(get_current_active_user)):
  216. async def majortel_calls_get(active_user=Depends(manager)):
  217. response = {"Calls": []}
  218. p = subprocess.Popen(['perl', '/opt/api_project_python/addCallQueue.pl', "get_calls"], stdout=subprocess.PIPE)
  219. calls = str(p.stdout.read())
  220. calls = calls.split("'")
  221. response1 = calls
  222. calls = calls[1].split("||")
  223. # cancello l'ultimo item della lista poichè, risultando vuoto dopo lo split,
  224. # genera errore "index out of range" nei successivi accessi alla lista
  225. del calls[-1]
  226. for call in calls:
  227. call = call.split("|")
  228. call_id = call[0]
  229. status = call[1]
  230. history = call[2]
  231. ntel = call[3]
  232. ackid = call[4]
  233. call_obj = {"id": call_id, "status": status, "history": history, "called_number": ntel, "ack_id": ackid}
  234. response["Calls"].append(call_obj)
  235. return response
  236. @app.get("/majortel/calls/{call_id}/", response_model=call, tags=["Majortel"])
  237. async def majortel_calls_id_get(call_id,active_user=Depends(manager)):
  238. p = subprocess.Popen(['perl', '/var/opt/FastAPI/addCallQueue.pl', "call_id", call_id],
  239. stdout=subprocess.PIPE)
  240. call = str(p.stdout.read())
  241. call = call.split("|")
  242. call_id = call[0].split("'")[1]
  243. status = call[1]
  244. # history = call[2]
  245. ntel = call[3]
  246. ackid = call[4]
  247. ackid = int(ackid.split("'")[0])
  248. response = {"id": call_id, "status": status, "called_number": ntel, "ack_id": ackid}
  249. return response
  250. # response_model=post_call,
  251. @app.post("/majortel/calls", response_model=post_call, tags=["Majortel"])
  252. async def majortel_calls_post(hw_id, ack_id, called_number, text_message="codice di riscontro ", timeout=30,
  253. retry=1, file: UploadFile = File(None),active_user=Depends(manager)):
  254. # controllo se l'hw_id corrisponde ai devices connessi
  255. current_device = os.popen('asterisk -rx "dongle show device state ' + hw_id + '"').read()
  256. current_device = current_device.split("\n")
  257. del current_device[0]
  258. if (current_device[0]):
  259. curr_time = datetime.now()
  260. call_id = str(curr_time.strftime('%y')) + str(curr_time.strftime('%m')) + str(curr_time.strftime('%d')) + str(
  261. curr_time.strftime('%H')) + str(curr_time.strftime('%M')) + str(curr_time.strftime('%S')) + str(
  262. curr_time.strftime('%f'))
  263. file_path = ""
  264. if (file):
  265. nomefile = file.filename
  266. extension = nomefile.split(".")[1]
  267. if (extension == "wav"):
  268. file_path = "/data/service/voip.majornet/ivr/" + call_id
  269. renamed_file = file_path + ".wav"
  270. with open(renamed_file, "wb") as f:
  271. shutil.copyfileobj(file.file, f)
  272. f.close()
  273. # p = subprocess.Popen(['(cd /tmp/audioCalls;/usr/local/bin/sox_wav2gsm)'],stdout=subprocess.PIPE)
  274. # os.popen('/usr/local/bin/sox_wav2gsm 1>/dev/null 2>/dev/null')
  275. subprocess.Popen(
  276. ['perl', '/opt/api_project_python/addCallQueue.pl', "voicegateway", "digiovine@afasystems.it", call_id,
  277. called_number, ack_id, text_message, "retry message here", timeout, retry, "yes", "notification_to",
  278. "notification_bcc", "setup", file_path, "fromemailssss", hw_id], stdout=subprocess.PIPE)
  279. response = {"id": call_id}
  280. return response
  281. else:
  282. return JSONResponse(status_code=404, content={"message": "Device not found"})
  283. @app.delete("/majortel/calls/", tags=["Majortel"],
  284. responses={200: {"model": httpResponse200}, 400: {"model": httpResponse400},
  285. 500: {"model": httpResponse500}})
  286. #async def majortel_calls_id_delete(call_id, current_user: User = Depends(get_current_active_user)):
  287. async def majortel_calls_id_delete(call_id,active_user=Depends(manager)):
  288. p = subprocess.Popen(['perl', '/opt/api_project_python/addCallQueue.pl', "delete_call", call_id],
  289. stdout=subprocess.PIPE)
  290. response = str(p.stdout.read())
  291. response = response.split("'")[1]
  292. if (response == "Success"):
  293. return JSONResponse(status_code=200, content={"message": "Success"})
  294. elif (response == "Not found"):
  295. return JSONResponse(status_code=404, content={"message": "Call not found"})
  296. else:
  297. return JSONResponse(status_code=500, content={"message": "Server error"})