Messenger bot is working!

parent be595c32
...@@ -873,6 +873,21 @@ def updateUserData(username, pwd, email, dhome, mhome, tts=False, ...@@ -873,6 +873,21 @@ def updateUserData(username, pwd, email, dhome, mhome, tts=False,
log.debug(qstring) log.debug(qstring)
return runOperation(qstring).addCallback(onRes) return runOperation(qstring).addCallback(onRes)
def getMessengerLinkedUsers():
qstring = "SELECT messenger_PSID,username FROM users WHERE messenger_PSID IS NOT NULL"
return runQuery(qstring)
def add_messenger_psid(psid, username):
def onRes(res):
if res>0:
return defer.succeed(username+" correctly updated")
else:
return defer.fail("User not found")
q = "UPDATE users SET messenger_PSID='%s' WHERE username='%s'" %(psid, username)
log.debug(qstring)
return runOperation(qstring).addCallback(onRes)
def getAllPermissions(user): def getAllPermissions(user):
qstring=""" qstring="""
......
...@@ -33,7 +33,7 @@ import subprocess ...@@ -33,7 +33,7 @@ import subprocess
import time, copy import time, copy
from web import proxy, mediaproxy from web import proxy, mediaproxy
from twisted.web import microdom as xml from twisted.web import microdom as xml
from singleton import clients, sequences, crontabs, statuses from singleton import clients, sequences, crontabs, statuses, messengerlinks
from singleton import oldboards as oldb from singleton import oldboards as oldb
from dmlib.utils import webutils as wu from dmlib.utils import webutils as wu
from dmlib import constants as C from dmlib import constants as C
...@@ -74,6 +74,10 @@ ALLIP=C.IKAP_BROADCAST ...@@ -74,6 +74,10 @@ ALLIP=C.IKAP_BROADCAST
ACTION_STATUS={} ACTION_STATUS={}
_MESSENGER_LINKS = messengerlinks.MessengerLinkRegistry()
_MESSENGER_PSID = messengerlinks.MessengerPSIDRegistry()
log = logging.getLogger( 'Core' ) log = logging.getLogger( 'Core' )
def converWday(wday): def converWday(wday):
...@@ -141,7 +145,7 @@ class domotikaService(service.Service): ...@@ -141,7 +145,7 @@ class domotikaService(service.Service):
self.thermoProgramLoop() self.thermoProgramLoop()
self.thermoprgloop=txcron.ScheduledCall(self.thermoProgramLoop) self.thermoprgloop=txcron.ScheduledCall(self.thermoProgramLoop)
self.thermoprgloop.start(CronSchedule('00 * * * *')) self.thermoprgloop.start(CronSchedule('00 * * * *'))
self.startMessengerLinkedUsers()
self.actiontimer.start(int(self.config.get("general", "action_status_timer"))) self.actiontimer.start(int(self.config.get("general", "action_status_timer")))
self.timer.start(int(self.config.get("ikapserver", "timeupdates"))) self.timer.start(int(self.config.get("ikapserver", "timeupdates")))
if self.config.get("general", "timeserver").lower() in ['yes','y','1','true', 'on']: if self.config.get("general", "timeserver").lower() in ['yes','y','1','true', 'on']:
...@@ -176,6 +180,15 @@ class domotikaService(service.Service): ...@@ -176,6 +180,15 @@ class domotikaService(service.Service):
self.config.get("geo", "openweathermap_appid")) self.config.get("geo", "openweathermap_appid"))
def startMessengerLinkedUsers(self):
def populateMessenger(res):
for r in res:
log.info(res)
_MESSENGER_PSID.add_link(r[0], r[1])
dmdb.getMessengerLinkedUsers().addCallback(populateMessenger)
def startVLC(self): def startVLC(self):
self.vlc = mediaproxy.VLCFactory() self.vlc = mediaproxy.VLCFactory()
self.vlc.start() self.vlc.start()
...@@ -2620,6 +2633,13 @@ class domotikaService(service.Service): ...@@ -2620,6 +2633,13 @@ class domotikaService(service.Service):
def web_on_voiceReceived(self, txt, confidence=0.0, lang="it"): def web_on_voiceReceived(self, txt, confidence=0.0, lang="it"):
return self.voiceRecognized(txt, confidence, lang, voicesrc='RestAPI') return self.voiceRecognized(txt, confidence, lang, voicesrc='RestAPI')
def web_on_add_messenger_psid(self, psid, authcode=False):
if not _MESSENGER_PSID.linkid_exists(psid):
if authcode and _MESSENGER_LINKS.linkid_exists(authcode):
username = _MESSENGER_LINKS.get_link(authcode)['username']
_MESSENGER_PSID.add_link(psid, username)
dmdb.add_messenger_psid(psid, username)
def plugin_on_registerEvent(self, event, pname, cback): def plugin_on_registerEvent(self, event, pname, cback):
log.debug("plugin_on_registerEvent "+str(event)+" "+str(cback)) log.debug("plugin_on_registerEvent "+str(event)+" "+str(cback))
events.registerEvent(event, pname, cback) events.registerEvent(event, pname, cback)
......
...@@ -12,6 +12,13 @@ import hashlib ...@@ -12,6 +12,13 @@ import hashlib
import hmac import hmac
import six import six
from domotika.singleton import messengerlinks
_MESSENGER_LINKS = messengerlinks.MessengerLinkRegistry()
_MESSENGER_PSID = messengerlinks.MessengerPSIDRegistry()
try: try:
#python2 #python2
from urllib import urlencode from urllib import urlencode
...@@ -25,7 +32,6 @@ log = logging.getLogger( 'Webgui' ) ...@@ -25,7 +32,6 @@ log = logging.getLogger( 'Webgui' )
BOTResource = RESTResource BOTResource = RESTResource
class BotCore(object): class BotCore(object):
path = "" path = ""
...@@ -41,8 +47,6 @@ class BaseBot(BotCore): ...@@ -41,8 +47,6 @@ class BaseBot(BotCore):
return 'Domotika BOTs API interface V1.0' return 'Domotika BOTs API interface V1.0'
def messengerValidator(): def messengerValidator():
def checkRequest(f): def checkRequest(f):
def new_f(self, request, *a, **kw): def new_f(self, request, *a, **kw):
...@@ -63,15 +67,19 @@ def messengerValidator(): ...@@ -63,15 +67,19 @@ def messengerValidator():
return new_f return new_f
return checkRequest return checkRequest
class MessengerBot(BotCore):
class MessengerCore(object):
def _cfgGet(self, keyword):
return self.core.configGet('messenger', keyword)
class MessengerBot(BotCore, MessengerCore):
path = "messenger" path = "messenger"
graphuri = 'https://graph.facebook.com/v2.6' graphuri = 'https://graph.facebook.com/v2.6'
#graphuri = 'http://192.168.4.2/v2.6' #graphuri = 'http://192.168.4.2/v2.6'
def __init__(self, *a, **kw):
super(MessengerBot, self).__init__(*a, **kw)
@property @property
def auth_args(self): def auth_args(self):
if not hasattr(self, '_auth_args'): if not hasattr(self, '_auth_args'):
...@@ -84,10 +92,6 @@ class MessengerBot(BotCore): ...@@ -84,10 +92,6 @@ class MessengerBot(BotCore):
self._auth_args = auth self._auth_args = auth
return self._auth_args return self._auth_args
def _cfgGet(self, keyword):
return self.core.configGet('messenger', keyword)
def _generateAppSecProof(self): def _generateAppSecProof(self):
if six.PY2: if six.PY2:
hmac_object = hmac.new(str(self._cfgGet('app_secret')), unicode(self._cfgGet('page_token')), hashlib.sha256) hmac_object = hmac.new(str(self._cfgGet('app_secret')), unicode(self._cfgGet('page_token')), hashlib.sha256)
...@@ -96,13 +100,13 @@ class MessengerBot(BotCore): ...@@ -96,13 +100,13 @@ class MessengerBot(BotCore):
return hmac_object.hexdigest() return hmac_object.hexdigest()
def _dataSent(self, res): def _dataSent(self, res):
log.info('OKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOK') log.debug('Messenger BOT Datasent OK')
log.info(res) log.debug(res)
def _dataError(self, res): def _dataError(self, res):
log.info('=======================================================================') log.info('Messenger BOT Datasent ERROR')
log.info(res) log.error(res)
log.info(res.value.reasons[0].printTraceback()) log.debug(res.value.reasons[0].printTraceback())
...@@ -128,8 +132,8 @@ class MessengerBot(BotCore): ...@@ -128,8 +132,8 @@ class MessengerBot(BotCore):
log.debug("New messenger bot request: "+str(kw)) log.debug("New messenger bot request: "+str(kw))
if 'object' in kw.keys() and kw['object'] == 'page' and 'entry' in kw.keys(): if 'object' in kw.keys() and kw['object'] == 'page' and 'entry' in kw.keys():
for entry in kw['entry']: for entry in kw['entry']:
#try: try:
if True: #if True:
pageID=entry['id'] pageID=entry['id']
timestamp=entry['time'] timestamp=entry['time']
messaging=entry['messaging'] messaging=entry['messaging']
...@@ -149,31 +153,84 @@ class MessengerBot(BotCore): ...@@ -149,31 +153,84 @@ class MessengerBot(BotCore):
self.receivedAccountLink(message) self.receivedAccountLink(message)
else: else:
log.info("Received unknow messaging webhook for messenger BOT: "+str(kw)) log.info("Received unknow messaging webhook for messenger BOT: "+str(kw))
#except: except:
# pass pass
return Response(200, 'OK') return Response(200, 'OK')
@route("/loginfailed")
def loginFailed(self, request, *a, **kw):
k = kw.keys()
if 'account_linking_token' in k and 'redirect_uri' in k:
log.info("Passed linking uri "+kw['redirect_uri'])
luri=kw['redirect_uri']
log.info("Authorization failed: redirecting to "+luri)
return Response(302, 'Authorization failed', headers={'Location': luri})
return Response(200, "Authorization failed." )
def receivedAuthentication(self, msg): def receivedAuthentication(self, msg):
pass log.info("Messenger bot received authentication: "+str(msg))
def receivedMessage(self, msg): def receivedMessage(self, msg):
def voiceResult(res):
log.info('VoiceResult: '+str(res))
if len(res) > 0:
if res[0] == 'Ok' and len(res) > 1:
try:
result = 'ho eseguito "'+" ".join(res[1]['clean']+'"')
except:
pass
else:
result = 'Spiacente, non ho trovato un comando corrispondente'
self.sendMessage(msg['sender']['id'], result)
log.info("Messenger bot received message: "+str(msg)) log.info("Messenger bot received message: "+str(msg))
message = u'Received: '+unicode(msg['message']['text']) message = u'Received: '+unicode(msg['message']['text'])
txt = unicode(msg['message']['text'])
senderid = msg['sender']['id']
if not 'is_echo' in msg['message'].keys() or not msg['message']['is_echo']: if not 'is_echo' in msg['message'].keys() or not msg['message']['is_echo']:
self.sendMessage(msg['sender']['id'], message) if not _MESSENGER_PSID.linkid_exists(senderid):
log.info(_MESSENGER_PSID.links)
if txt == u'hello' or txt == u'ciao':
self.sendMessage(senderid, 'Hello, how can i help you?')
elif txt == u'?' or txt == u'help':
self.sendMessage(senderid, 'you can\'t do that.')
elif txt == u'login':
self.sendAuthRequest(senderid)
else:
self.sendMessage(senderid, txt+" come se fosse antani")
else:
if txt == u'hello' or txt == u'ciao':
self.sendMessage(senderid, 'Hello %s, how can i help you?' %(_MESSENGER_PSID.get_link(senderid)))
elif txt == u'?' or txt == u'help':
self.sendMessage(senderid, 'Ok, devo ancora implementare l\'aiuto!')
elif txt == u'logout':
self.sendMessage(senderid, 'Ok, devo ancora implementare anche il logout')
else:
self.sendMessage(senderid, 'Io ci provo a dare questo comando...')
self.core.voiceReceived(txt, confidence=1.0, lang="it").addCallback(voiceResult)
def receivedDeliveryConfirmation(self, msg): def receivedDeliveryConfirmation(self, msg):
pass log.info("Messenger bot received delivery confirmation: "+str(msg))
def receivedPostback(self, msg): def receivedPostback(self, msg):
pass log.info("Messenger bot received postback: "+str(msg))
def receivedMessageRead(self, msg): def receivedMessageRead(self, msg):
log.info("Messenger bot received message read: "+str(msg)) log.info("Messenger bot received message read: "+str(msg))
def receivedAccountLink(self, msg): def receivedAccountLink(self, msg):
pass log.info("Messenger bot received accountlink: "+str(msg))
senderid = msg['sender']['id']
recipient = msg['recipient']['id']
status = msg['account_linking']['status']
authcode = msg['account_linking']['authorization_code']
if status == u'linked':
self.core.add_messenger_psid(senderid, authcode)
def sendMessage(self, recipient_id, message): def sendMessage(self, recipient_id, message):
payload = { payload = {
...@@ -186,6 +243,50 @@ class MessengerBot(BotCore): ...@@ -186,6 +243,50 @@ class MessengerBot(BotCore):
} }
return self.sendAPI(payload) return self.sendAPI(payload)
def sendAuthRequest(self, recipient_id):
payload = {
'recipient': {
'id': recipient_id
},
'message': {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [{
"title": self._cfgGet('auth_title'),
"image_url": self._cfgGet('auth_img'),
"buttons": [{
"type": "account_link",
"url": self._cfgGet('auth_host')
}]
}]
}
}
}
}
return self.sendAPI(payload)
class MessengerBotAuth(BotCore, MessengerCore):
path="messenger"
@route("/", Http.GET)
def linkUser(self, request, *a, **kw):
k = self.session.saveargs.keys()
if 'account_linking_token' in k and 'redirect_uri' in k:
luri=self.session.saveargs['redirect_uri'][0]
log.debug(str(self.session.mind.perms))
hmac_object = hmac.new(str(self.session.mind.perms.username), unicode(self._cfgGet('page_token')), hashlib.sha256)
_MESSENGER_LINKS.add_link(hmac_object.hexdigest(), self.session.mind.perms)
luri = luri+"&authorization_code="+hmac_object.hexdigest()
log.info("Authorization succeed: redirecting to "+luri)
headers={'Location': luri}
return Response(302, 'Authorization succeed', headers=headers)
return Response(200, "Authorization Succeed." )
BotApiList=( BotApiList=(
BaseBot, BaseBot,
...@@ -207,6 +308,25 @@ class BotPages(rend.Page): ...@@ -207,6 +308,25 @@ class BotPages(rend.Page):
request = inevow.IRequest(ctx) request = inevow.IRequest(ctx)
self.session = inevow.ISession(ctx) self.session = inevow.ISession(ctx)
request.setHeader("pragma", "no-cache") request.setHeader("pragma", "no-cache")
request.postpath=['/',name]+request.postpath #request.postpath=['/', name]+request.postpath
request.postpath=['/']+request.postpath
log.info("BOT: "+str(request.postpath))
return BOTResource([x(self.core, self.session) for x in BotApiList]) return BOTResource([x(self.core, self.session) for x in BotApiList])
BotAuthList=(
BaseBot,
MessengerBotAuth
)
class BotAuth(rend.Page):
def childFactory(self, ctx, name):
request = inevow.IRequest(ctx)
self.session = inevow.ISession(ctx)
request.setHeader("pragma", "no-cache")
#request.postpath=['/', name]+request.postpath
request.postpath=['/']+request.postpath
log.info("BOTAUTH: "+str(request.postpath))
return BOTResource([x(self.core, self.session) for x in BotAuthList])
...@@ -51,10 +51,6 @@ import proxy, mediaproxy, rest, bot ...@@ -51,10 +51,6 @@ import proxy, mediaproxy, rest, bot
import os, sys import os, sys
from twisted.python import reflect from twisted.python import reflect
from twisted import cred from twisted import cred
import twisted.cred.portal
import twisted.cred.credentials
import twisted.cred.checkers
import twisted.cred.error
from twisted.internet import defer from twisted.internet import defer
from nevow import appserver from nevow import appserver
import time import time
...@@ -112,8 +108,17 @@ class RootPage(rend.Page): ...@@ -112,8 +108,17 @@ class RootPage(rend.Page):
def renderHTML(self, ctx): def renderHTML(self, ctx):
request = inevow.IRequest(ctx) request = inevow.IRequest(ctx)
session = inevow.ISession(ctx)
return rend.Page.renderHTTP(self, ctx) return rend.Page.renderHTTP(self, ctx)
def child_botauth(self, ctx):
session = inevow.ISession(ctx)
log.debug("BOT AUTH callback received")
botauth = bot.BotAuth()
botauth.core = self.core
return botauth
def child_rest(self, ctx): def child_rest(self, ctx):
if str(self.core.configGet('web', 'enablerestgui')).lower() in ['yes', '1', 'y','true']: if str(self.core.configGet('web', 'enablerestgui')).lower() in ['yes', '1', 'y','true']:
self.rest = rest.RestPages() self.rest = rest.RestPages()
...@@ -337,8 +342,50 @@ class RootPage(rend.Page): ...@@ -337,8 +342,50 @@ class RootPage(rend.Page):
### Authentication ### Authentication
from twisted.cred.error import UnauthorizedLogin
from nevow import url
class SessionWrapper(guard.SessionWrapper): class SessionWrapper(guard.SessionWrapper):
def checkLogin(self, ctx, session, segments, *a, **kw):
try:
session.saveargs = session.args
except:
pass
request = inevow.IRequest(ctx)
return guard.SessionWrapper.checkLogin(self, ctx, session, segments, *a, **kw)
def incorrectLoginError(self, error, ctx, segments, loginFailure):
""" Used as an errback upon failed login, returns a 2-tuple of a failure URL
with the query argument 'login-failure' set to the parameter
loginFailure, and an empty list of segments, to redirect to that URL.
The basis for this error URL, i.e. the part before the query string, is
taken either from the 'referer' header from the given request if one
exists, or a computed URL that points at the same page that the user is
currently looking at to attempt login. Any existing query string will
be stripped.
"""
request = inevow.IRequest(ctx)
session = inevow.ISession(ctx)
error.trap(UnauthorizedLogin)
referer = request.getHeader("referer")
if 'botauth' in segments and len(segments) is 3:
segments = ('bot', segments[1], 'loginfailed', '')
u = guard.urlToChild(ctx, *segments)
for k in session.saveargs.keys():
if k not in ['username', 'password'] and session.saveargs[k][0] not in ['Login']:
u = u.add(k, session.saveargs[k][0])
else:
if referer is not None:
u = url.URL.fromString(referer)
else:
u = guard.urlToChild(ctx, *segments)
u = u.clear()
u = u.add('login-failure', loginFailure)
return u, ()
def renderHTTP( self, ctx): def renderHTTP( self, ctx):
request = inevow.IRequest(ctx) request = inevow.IRequest(ctx)
host=request.getHeader('host') host=request.getHeader('host')
...@@ -355,13 +402,13 @@ class SessionWrapper(guard.SessionWrapper): ...@@ -355,13 +402,13 @@ class SessionWrapper(guard.SessionWrapper):
name = "/".join(segments) name = "/".join(segments)
if name=='': if name=='':
name="/" name="/"
log.debug("SessionWrapper locateChild "+str(name)+" from IP:"+str(request.getClientIP())) log.info("SessionWrapper locateChild "+str(name)+" from IP:"+str(request.getClientIP()))
if name: if name:
if name.startswith('mediaproxy') and request.getClientIP()=='127.0.0.1': if name.startswith('mediaproxy') and request.getClientIP()=='127.0.0.1':
mp = mediaproxy.MediaStreamProxy() mp = mediaproxy.MediaStreamProxy()
mp.core = self.core mp.core = self.core
return (mp, segments[1:]) return (mp, segments[1:])
if name.startswith('bot'): if name.startswith('bot/'):
# Bypass for chat bots # Bypass for chat bots
chatbot = bot.BotPages() chatbot = bot.BotPages()
chatbot.core = self.core chatbot.core = self.core
...@@ -407,7 +454,7 @@ class SessionWrapper(guard.SessionWrapper): ...@@ -407,7 +454,7 @@ class SessionWrapper(guard.SessionWrapper):
request.args["username"] = [request.getUser()] request.args["username"] = [request.getUser()]
request.args["password"] = [request.getPassword()] request.args["password"] = [request.getPassword()]
log.debug("Calling Guard..."+str(request.args)) log.info("Calling Guard..."+str(request.args))
return guard.SessionWrapper.locateChild(self, ctx, segments) return guard.SessionWrapper.locateChild(self, ctx, segments)
...@@ -552,14 +599,15 @@ class LoginPage(rend.Page): ...@@ -552,14 +599,15 @@ class LoginPage(rend.Page):
return '{"data": "SLOGGEDOUT", "uri": "'+request.path+'", "ts": '+str(time.time())+', "result": "succeed"}' return '{"data": "SLOGGEDOUT", "uri": "'+request.path+'", "ts": '+str(time.time())+', "result": "succeed"}'
if not rme: if not rme:
log.info("LOGIN FORM FOR PATH "+request.path) log.info("LOGIN FORM FOR PATH "+request.uri)
return self.getStandardHTML(request.path) return self.getStandardHTML(request.uri)
else: else:
log.info("LOGIN FROM COOKIE FOR PATH "+request.path) log.info("LOGIN FROM COOKIE FOR PATH "+request.uri)
return rme.addCallback(self.rmelogin, request, rmec) return rme.addCallback(self.rmelogin, request, rmec)
def getStandardHTML(self, path): def getStandardHTML(self, path):
log.info(path)
html = self.html.replace("@PATH@", '/__login__'+path) html = self.html.replace("@PATH@", '/__login__'+path)
html = html.replace("@USERNAME@", '') html = html.replace("@USERNAME@", '')
html = html.replace("@PASSWORD@", '') html = html.replace("@PASSWORD@", '')
...@@ -591,7 +639,7 @@ class LoginPage(rend.Page): ...@@ -591,7 +639,7 @@ class LoginPage(rend.Page):
req.addCookie("Domotikad_rme", has, req.addCookie("Domotikad_rme", has,
path="/", secure=True, expires=expire) path="/", secure=True, expires=expire)
html = self.html.replace("@PATH@", '/__login__'+req.path) html = self.html.replace("@PATH@", '/__login__'+req.uri)
html = html.replace("@USERNAME@", str(user.username)) html = html.replace("@USERNAME@", str(user.username))
html = html.replace("@PASSWORD@", str(lp)) html = html.replace("@PASSWORD@", str(lp))
html = html.replace("@CHECKED@", "checked") html = html.replace("@CHECKED@", "checked")
...@@ -609,7 +657,6 @@ class LoginPage(rend.Page): ...@@ -609,7 +657,6 @@ class LoginPage(rend.Page):
chatbot.core = self.core chatbot.core = self.core
return chatbot return chatbot
def childFactory(self, ctx, name): def childFactory(self, ctx, name):
log.debug("Login childFactory") log.debug("Login childFactory")
request = inevow.IRequest(ctx) request = inevow.IRequest(ctx)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment