Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

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