25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

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