|
@@ -250,7 +250,7 @@ async def celCallback(mngr: Manager, msg: Message):
|
|
|
cid = app.cache['usermap'][firstMessage.CallerIDnum]
|
|
cid = app.cache['usermap'][firstMessage.CallerIDnum]
|
|
|
uid = firstMessage.LinkedID
|
|
uid = firstMessage.LinkedID
|
|
|
if (msg.EventName == 'CHAN_START') and (lid != msg.UniqueID) and (not msg.Channel.startswith('Local/')):
|
|
if (msg.EventName == 'CHAN_START') and (lid != msg.UniqueID) and (not msg.Channel.startswith('Local/')):
|
|
|
- if (True or (firstMessage.Context == 'from-pstn') or (firstMessage.get('groupCall',False))):#all calls
|
|
|
|
|
|
|
+ if (msg.CallerIDnum!=''): # or (firstMessage.Context == 'from-pstn') or (firstMessage.get('groupCall',False))):#all calls
|
|
|
device = msg.CallerIDnum
|
|
device = msg.CallerIDnum
|
|
|
user = app.cache['usermap'][device]
|
|
user = app.cache['usermap'][device]
|
|
|
did = firstMessage.Exten
|
|
did = firstMessage.Exten
|
|
@@ -357,6 +357,17 @@ async def celCallback(mngr: Manager, msg: Message):
|
|
|
if (lid in app.cache['calls']):
|
|
if (lid in app.cache['calls']):
|
|
|
app.cache['calls'][lid][varname]=value
|
|
app.cache['calls'][lid][varname]=value
|
|
|
|
|
|
|
|
|
|
+ if (msg.EventName == 'USER_DEFINED') and (msg.UserDefType == 'CALLBACK_POSTFIX'):
|
|
|
|
|
+ callback_type = msg.AppData.split(',')[1]
|
|
|
|
|
+ postfix = msg.AppData.split(',')[2]
|
|
|
|
|
+ values = msg.AppData.split(',')[3:]
|
|
|
|
|
+ _cb = {'asteriskCallId':msg.LinkedID}
|
|
|
|
|
+ for value in values:
|
|
|
|
|
+ vn,vv = value.split('=')
|
|
|
|
|
+ _cb[vn] = vv
|
|
|
|
|
+ reply = await doCallbackPostfix(callback_type,postfix, _cb)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
async def getCDR(start=None,
|
|
async def getCDR(start=None,
|
|
|
end=None,
|
|
end=None,
|
|
|
table='cdr',
|
|
table='cdr',
|
|
@@ -482,6 +493,22 @@ async def doCallback(entity, msg):
|
|
|
app.logger.warning('No callback url defined for {}'.format(entity))
|
|
app.logger.warning('No callback url defined for {}'.format(entity))
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
|
|
+async def doCallbackPostfix(entity,postfix, msg):
|
|
|
|
|
+ row = await db.fetch_one(query='SELECT url FROM callback_urls WHERE device = :device', values={'device': entity})
|
|
|
|
|
+ if ((row is not None) and (row['url'].startswith('http')) and ('blackhole' not in row['url'])):
|
|
|
|
|
+ url = row["url"]+'/'+postfix
|
|
|
|
|
+ app.logger.warning(f'''POST {url} data: {str(msg)}''')
|
|
|
|
|
+ if not 'HTTP_CLIENT' in app.config:
|
|
|
|
|
+ await initHttpClient()
|
|
|
|
|
+ try:
|
|
|
|
|
+ reply = await app.config['HTTP_CLIENT'].post(url, json=msg)
|
|
|
|
|
+ return reply
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ app.logger.warning('callback error {}'.format(url))
|
|
|
|
|
+ else:
|
|
|
|
|
+ app.logger.warning('No callback url defined for {}'.format(entity))
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
@app.before_first_request
|
|
@app.before_first_request
|
|
|
async def initHttpClient():
|
|
async def initHttpClient():
|
|
|
app.config['HTTP_CLIENT'] = aiohttp.ClientSession(loop=main_loop,
|
|
app.config['HTTP_CLIENT'] = aiohttp.ClientSession(loop=main_loop,
|
|
@@ -1095,11 +1122,12 @@ class Originate(Resource):
|
|
|
# else:
|
|
# else:
|
|
|
# return errorReply(reply.message)
|
|
# return errorReply(reply.message)
|
|
|
|
|
|
|
|
-@app.route('/autocall1/<numberA>/<numberB>')
|
|
|
|
|
-class Autocall1(Resource):
|
|
|
|
|
|
|
+@app.route('/autocall/<numberA>/<numberB>')
|
|
|
|
|
+class Autocall(Resource):
|
|
|
@authRequired
|
|
@authRequired
|
|
|
@app.param('numberA', 'User calling first', 'path')
|
|
@app.param('numberA', 'User calling first', 'path')
|
|
|
@app.param('numberB', 'user calling after numberA enter DTMF 2', 'path')
|
|
@app.param('numberB', 'user calling after numberA enter DTMF 2', 'path')
|
|
|
|
|
+ @app.param('callid', 'callid to be returned in callback', 'query')
|
|
|
@app.response(HTTPStatus.OK, 'Json reply')
|
|
@app.response(HTTPStatus.OK, 'Json reply')
|
|
|
@app.response(HTTPStatus.UNAUTHORIZED, 'Authorization required')
|
|
@app.response(HTTPStatus.UNAUTHORIZED, 'Authorization required')
|
|
|
async def get(self, numberA, numberB):
|
|
async def get(self, numberA, numberB):
|
|
@@ -1107,14 +1135,16 @@ class Autocall1(Resource):
|
|
|
'''
|
|
'''
|
|
|
if (not request.admin):
|
|
if (not request.admin):
|
|
|
abort(401)
|
|
abort(401)
|
|
|
-
|
|
|
|
|
|
|
+ callid = request.args.get('callid', None)
|
|
|
_act = { 'Action':'Originate',
|
|
_act = { 'Action':'Originate',
|
|
|
- 'Channel':'Local/{}@autocall1-legA'.format(numberA),
|
|
|
|
|
- 'Context':'autocall1-legB',
|
|
|
|
|
|
|
+ 'Channel':'Local/{}@autocall-legA'.format(numberA),
|
|
|
|
|
+ 'Context':'autocall-legB',
|
|
|
'Exten':numberB,
|
|
'Exten':numberB,
|
|
|
'Priority': '1',
|
|
'Priority': '1',
|
|
|
'Async':'true',
|
|
'Async':'true',
|
|
|
- 'Callerid': '{} <{}>'.format(2898, 2898)}
|
|
|
|
|
|
|
+ 'Callerid': '{} <{}>'.format(1000, 1000),
|
|
|
|
|
+ 'Variable': '__callid={}'.format(callid)
|
|
|
|
|
+ }
|
|
|
app.logger.warning(_act)
|
|
app.logger.warning(_act)
|
|
|
await manager.send_action(_act)
|
|
await manager.send_action(_act)
|
|
|
return successfullyOriginated(numberA, numberB)
|
|
return successfullyOriginated(numberA, numberB)
|
|
@@ -1557,5 +1587,29 @@ class QueueLeaveCallback(Resource):
|
|
|
url = row['url']
|
|
url = row['url']
|
|
|
return successCommonCallbackURL('queueLeave', url)
|
|
return successCommonCallbackURL('queueLeave', url)
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/callback/<type>')
|
|
|
|
|
+class CommonCallback(Resource):
|
|
|
|
|
+ @authRequired
|
|
|
|
|
+ @app.param('type', 'Callback type', 'path')
|
|
|
|
|
+ @app.param('url', 'used to set the Callback url for the autocall', 'query')
|
|
|
|
|
+ @app.response(HTTPStatus.OK, 'JSON data {"url":url}')
|
|
|
|
|
+ @app.response(HTTPStatus.UNAUTHORIZED, 'Authorization required')
|
|
|
|
|
+ async def get(self,type):
|
|
|
|
|
+ '''Returns and sets Autocall callback url.
|
|
|
|
|
+ '''
|
|
|
|
|
+ if not request.admin:
|
|
|
|
|
+ abort(401)
|
|
|
|
|
+ url = request.args.get('url', None)
|
|
|
|
|
+ if url is not None:
|
|
|
|
|
+ await db.execute(query='REPLACE INTO callback_urls (device, url) VALUES (:device, :url)',
|
|
|
|
|
+ values={'device': type,'url': url})
|
|
|
|
|
+ else:
|
|
|
|
|
+ row = await db.fetch_one(query='SELECT url FROM callback_urls WHERE device = :device',
|
|
|
|
|
+ values={'device': type})
|
|
|
|
|
+ if row is not None:
|
|
|
|
|
+ url = row['url']
|
|
|
|
|
+ return successCommonCallbackURL(type, url)
|
|
|
|
|
+
|
|
|
manager.connect()
|
|
manager.connect()
|
|
|
app.run(loop=main_loop, host='0.0.0.0', port=app.config['PORT'])
|
|
app.run(loop=main_loop, host='0.0.0.0', port=app.config['PORT'])
|