utils.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #!/usr/bin/env python3
  2. from dataclasses import dataclass, asdict
  3. from panoramisk import Message
  4. from datetime import datetime as dt
  5. from datetime import timedelta as td
  6. TRUEs = ('true', '1', 'y', 'yes')
  7. NONEs = (None,'none','')
  8. externalContexts = ('ext-group',
  9. 'ext-queues',
  10. 'ext-local',
  11. 'from-trunk',
  12. 'from-digital',
  13. 'from-pstn',
  14. 'from-did-direct')
  15. # userstate presencestate maping:
  16. _ustates = ['idle', 'inuse', 'busy', 'unavailable', 'ringing', 'inuse&ringing','hold', 'inuse&hold'] #presence:
  17. _states = [['available', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy'], #not_set
  18. ['unavailable', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy'], #unavailable
  19. ['available', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy'], #available
  20. ['away', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy'], #away
  21. ['available', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy'], #xa
  22. ['available', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy'], #chat
  23. ['dnd', 'busy', 'busy', 'unavailable', 'ringing', 'busy', 'busy', 'busy']] #dnd
  24. _pstates = ['not_set',
  25. 'unavailable',
  26. 'available',
  27. 'away',
  28. 'xa',
  29. 'chat',
  30. 'dnd']
  31. # combinedStates[userstate][presencestate]=combinedState
  32. combinedStates = {_u: {_p: _states[_pstates.index(_p)][_ustates.index(_u)] for _p in _pstates} for _u in _ustates}
  33. presenceStates = _pstates
  34. NO_AUTH_ROUTES = ('/ui','/openapi.json','/favicon.ico')
  35. SWAGGER_JS_URL = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.37.2/swagger-ui-bundle.js"
  36. SWAGGER_CSS_URL = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.37.2/swagger-ui.min.css"
  37. SWAGGER_TEMPLATE = '''
  38. <head>
  39. <link type="text/css" rel="stylesheet" href="{{ css_url }}">
  40. <title>{{ title }}</title>
  41. </head>
  42. <body>
  43. <div id="swagger-ui"></div>
  44. <script src="{{ js_url }}"></script>
  45. <script>
  46. const ui = SwaggerUIBundle({
  47. deepLinking: true,
  48. dom_id: "#swagger-ui",
  49. layout: "BaseLayout",
  50. presets: [
  51. SwaggerUIBundle.presets.apis,
  52. SwaggerUIBundle.SwaggerUIStandalonePreset
  53. ],
  54. showExtensions: true,
  55. showCommonExtensions: true,
  56. url: "/openapi.json"
  57. });
  58. </script>
  59. </body>'''
  60. def parseDatetime(dateString):
  61. _dt = None
  62. if dateString is not None:
  63. try:
  64. _dt = dt.strptime(dateString, '%d%m%Y%H%M%S')
  65. except ValueError:
  66. pass
  67. if _dt is None:
  68. try:
  69. _dt = dt.fromtimestamp(int(dateString))
  70. except ValueError:
  71. pass
  72. if _dt is None:
  73. try:
  74. _dt = dt.fromisoformat(dateString)
  75. except ValueError:
  76. pass
  77. return _dt
  78. def freepbxExternalContext(context):
  79. if ((context in externalContexts) or
  80. (context.startswith('from-trunk')) or
  81. (context.startswith('from-did')) or
  82. (context.startswith('ivr-'))):
  83. return True
  84. return False
  85. def followMe2DevState(followMeState):
  86. if followMeState == 'DIRECT':
  87. return 'INUSE'
  88. if followMeState == 'EXTENSION':
  89. return 'NOT_INUSE'
  90. return 'INVALID'
  91. @dataclass
  92. class QueueMember:
  93. user: str
  94. name: str = ''
  95. location: str = ''
  96. membership: str = ''
  97. stateinterface: str = ''
  98. status: str = ''
  99. def fromMessage(self, _m: Message):
  100. for key in asdict(self).keys():
  101. if key in _m:
  102. setattr(self, key, _m[key])
  103. return self
  104. @dataclass
  105. class GlobalVars:
  106. FMDEVSTATE: str = ''
  107. QUEDEVSTATE: str = ''
  108. QUEUETOGGLE: str = ''
  109. QUEUEPAUSETOGGLE: str = ''
  110. INTERCOMCODE: str = ''
  111. CAMPONTOGGLE: str = ''
  112. DNDDEVSTATE: str = ''
  113. CFDEVSTATE: str = ''
  114. def d(self):
  115. return asdict(self)
  116. def jsonAPIReply(status='success', data=None, message=None):
  117. return {'status':status, 'data': data, 'message': message}
  118. def errorReply(message=None):
  119. return jsonAPIReply(status='error', data=None, message=message)
  120. def successReply(data=None,message=None):
  121. return jsonAPIReply(status='success', data=data, message=message)
  122. def noUser(user):
  123. return errorReply('User {} does not exist'.format(user))
  124. def noDevice(device):
  125. return errorReply('Device {} does not exist'.format(device))
  126. def noUserDevice(user):
  127. return errorReply('User {} does not exist or is not bound to device'.format(user))
  128. def noUserChannel(user):
  129. return errorReply('User {} does not have active calls'.format(user))
  130. def stateCacheEmpty():
  131. return errorReply('Users states cache update failed')
  132. def invalidState(state):
  133. return errorReply('Invalid state "{}" provided'.format(state))
  134. def alreadyBound(user, device):
  135. return errorReply('User {} is already bound to device {}'.format(user, device))
  136. def bindError(user, device):
  137. return errorReply('Failed binding user {} to device {}'.format(user, device))
  138. def hintError(user, device):
  139. return errorReply('Failed setting hint for user {} on device {}'.format(user, device))
  140. def noUserBound(device):
  141. return errorReply('No user is bound to device {}'.format(device))
  142. def successfullyTransfered(userA, userB):
  143. return successReply({'userA':userA,'userB':userB},
  144. 'Call was successfully transfered from user {} to user {}'.format(userA, userB))
  145. def successfullyBound(user, device):
  146. return successReply({'user':user,'device':device},
  147. 'User {} is successfully bound to device {}'.format(user, device))
  148. def successfullyUnbound(user, device):
  149. return successReply({'user':user,'device':device},
  150. 'User {} was successfully unbound from device {}'.format(user, device))
  151. def successfullySetState(user, state):
  152. return successReply({'user':user,'state':state},
  153. 'State "{}" was successfully set for user {}'.format(state, user))