From 1adb32ad096ebeed4f977833a61380a4493e3cf5 Mon Sep 17 00:00:00 2001 From: Michel Alexandre Salim Date: Tue, 29 Sep 2009 04:27:20 -0400 Subject: [PATCH] User data now stored in SQLite database. Access is through Storm ORM so the actual database implementation can be swapped out --- bot.py | 39 ++++++++++++++++-------- datamodel.py | 67 +++++++++++++++++++++++++++++++++++++++++ msg_eval.py | 85 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 156 insertions(+), 35 deletions(-) create mode 100644 datamodel.py diff --git a/bot.py b/bot.py index 1cc5cbc..c5d9aa7 100755 --- a/bot.py +++ b/bot.py @@ -21,19 +21,32 @@ from plugins import twitter import os, sys, time -import msg_eval +from msg_eval import MsgEval +import datamodel t = twitter.Twitter() - -while True: - # check if there is a request - for m in t.get_messages(): - print m['sender_screen_name'], m['text'] - try: - result = msg_eval.eval(m) - except Exception as e: - result = str(type(e)) + ": " + str(e) - t.send_message(m['sender_screen_name'], result) - - time.sleep(30) +msg_eval = MsgEval(t) + +try: + while True: + # check if there is a request + # reverse the list, due to reverse chronological order + # to make sure later commands overwrite earlier ones + for m in t.get_messages()[::-1]: + sys.stdout.write(m['sender_screen_name'] + ": " + m['text'] + "\n") + try: + result = msg_eval.eval(m) + except Exception as e: + result = str(type(e)) + ": " + str(e) + if result: + print result + t.send_message(m['sender_screen_name'], result) + else: + sys.stdout.write("Message processed silently.\n") + + time.sleep(30) + +except KeyboardInterrupt as e: + sys.stdout.write("Quitting\n") + msg_eval.quit() diff --git a/datamodel.py b/datamodel.py new file mode 100644 index 0000000..03d7e46 --- /dev/null +++ b/datamodel.py @@ -0,0 +1,67 @@ +""" +Copyright (C) 2009 Michel Alexandre Sailm. All rights reserved. + +This file is part of Hircus ConnectBot. + +Hircus ConnectBot is free software: you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +Hircus ConnectBot is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with Hircus ConnectBot. If not, see +. +""" + +from storm.locals import * +import os + +DB_BACKEND = 'sqlite:' +DB_FILE = os.path.join(os.getenv("HOME"), + ".config", + "hircus_contactbot", + "contacts.db") + +DB_INITSQL = \ + """ +CREATE TABLE person + (id INTEGER PRIMARY KEY, + screen_name VARCHAR, + phone VARCHAR, + location VARCHAR) +""" + +class Person(object): + __storm_table__ = "person" + id = Int(primary=True) + screen_name = Unicode() + phone = Unicode() + location = Unicode() + +class MsgDB(object): + def __init__(self, db_backend=DB_BACKEND, db_file=DB_FILE): + db_exists = db_file and os.path.exists(db_file) + self.db = create_database(db_backend+db_file) + self.store = Store(self.db) + if not db_exists: + # new database, needs initializing + print "Initializing DB" + self.store.execute(DB_INITSQL) + print "DB initialized" + self.store.flush() + self.store.commit() + + def find_person(self, name): + person = self.store.find(Person, \ + Person.screen_name == name).one() + if not person: + person = Person() + person.screen_name = name + self.store.add(person) + + return person diff --git a/msg_eval.py b/msg_eval.py index a666e43..bc06f48 100644 --- a/msg_eval.py +++ b/msg_eval.py @@ -18,6 +18,8 @@ . """ +import datamodel + class MsgError(Exception): def __init__(self, value): self.value = value @@ -25,32 +27,71 @@ def __init__(self, value): def __str__(self): return repr(self.value) -def eval(msg): - sender = msg['sender_screen_name'] - cmdtext = msg['text'] - cmds = cmdtext.split() +class MsgEval(object): + def __init__(self, agent): + self.__msg_db = datamodel.MsgDB() + self.__agent = agent - if len(cmds) < 2: - raise MsgError("Insufficient arguments") + def eval(self, msg): + sender = unicode(msg['sender_screen_name']) + cmdtext = msg['text'] + cmds = cmdtext.split() - if cmds[0] == "set": - cmds = cmds[1:] if len(cmds) < 2: - raise MsgError("Invalid arguments: " + cmds) - if cmds[0] == "phone": - return "new phone number for " + sender + " is " + cmds[1] - elif cmds[0] == "location": - return "new location for " + sender + " is " + \ - cmdtext[cmdtext.index(cmds[1]):] + raise MsgError("Insufficient arguments") + + if cmds[0] == "set": + cmds = cmds[1:] + if len(cmds) < 2: + raise MsgError("Invalid arguments: " + cmds) + if cmds[0] == "phone": + phone = unicode(cmds[1]) + person = self.__msg_db.find_person(sender) + person.phone = phone + self.__msg_db.store.flush() + #return "new phone number for " + sender + " is " + cmds[1] + return None + elif cmds[0] == "location": + location = unicode(cmdtext[cmdtext.index(cmds[1]):]) + person = self.__msg_db.find_person(sender) + person.location = location + self.__msg_db.store.flush() + #return "new location for " + sender + " is " + location + return None + else: + raise KeyError(cmds[0]) + elif cmds[0] == "phone": + target = unicode(cmds[1]) + if sender==target or self.__agent.friends_p(target, sender): + target_person = self.__msg_db.find_person(target) + if target_person.phone: + return "%s can be reached at %s." \ + % (target, target_person.phone) + else: + return "%s has not left a number." \ + % (target,) + else: + return "%s's phone number is on a need-to-know basis." \ + % (target,) + + elif cmds[0] == "location": + print "Got a location request!" + target = unicode(cmds[1]) + if sender==target or self.__agent.friends_p(target, sender): + target_person = self.__msg_db.find_person(target) + if target_person.location: + return "%s is currently in %s." \ + % (target, target_person.location) + else: + return "%s's whereabout is unknown." \ + % (target,) + else: + return "%s's whereabout is on a need-to-know basis." \ + % (target,) else: raise KeyError(cmds[0]) - elif cmds[0] == "phone": - raise NotImplementedError() - elif cmds[0] == "location": - raise NotImplementedError() - else: - raise KeyError(cmds[0]) - - + def quit(self): + # commit remaining changes + self.__msg_db.store.commit()