from pyircbot.modulebase import ModuleBase,ModuleHook import datetime import time import math class Calc(ModuleBase): def __init__(self, bot, moduleName): ModuleBase.__init__(self, bot, moduleName); self.hooks=[ModuleHook("PRIVMSG", self.calc)] self.timers={} self.sqlite = self.bot.getBestModuleForService("sqlite") if self.sqlite==None: self.log.error("Calc: SQLIite service is required.") return self.sql = self.sqlite.opendb("calc.db") if not self.sql.tableExists("calc_addedby"): c = self.sql.getCursor() c.execute(""" CREATE TABLE `calc_addedby` ( `id` INTEGER PRIMARY KEY, `username` varchar(32), `userhost` varchar(128) ) ; """) c.close() if not self.sql.tableExists("calc_channels"): c = self.sql.getCursor() c.execute(""" CREATE TABLE `calc_channels` ( `id` INTEGER PRIMARY KEY, `channel` varchar(32) ) ; """) if not self.sql.tableExists("calc_definitions"): c = self.sql.getCursor() c.execute(""" CREATE TABLE `calc_definitions` ( `id` INTEGER PRIMARY KEY, `word` INTEGET, `definition` varchar(512), `addedby` INTEGER, `date` timestamp, `status` varchar(16) ) ; """) if not self.sql.tableExists("calc_words"): c = self.sql.getCursor() c.execute(""" CREATE TABLE `calc_words` ( `id` INTEGER PRIMARY KEY, `channel` INTEGER, `word` varchar(512), `status` varchar(32), unique(`channel`,`word`) ); """) c.close() def timeSince(self, channel, timetype): if not channel in self.timers: self.createDefaultTimers(channel) return time.time()-self.timers[channel][timetype] def updateTimeSince(self, channel, timetype): if not channel in self.timers: self.createDefaultTimers(channel) self.timers[channel][timetype] = time.time() def createDefaultTimers(self, channel): self.timers[channel]={"add":0, "calc":0, "calcspec":0, "match":0} def remainingToStr(self, total, elasped): remaining = total-elasped minutes = int(math.floor(remaining/60)) seconds = int(remaining - (minutes*60)) return "Please wait %s minute(s) and %s second(s)." % (minutes, seconds) def calc(self, args, prefix, trailing): # Channel only if not args[0][0]=="#": return sender = self.bot.decodePrefix(prefix) foundCalc = False commandFound = "" for cmd in self.config["cmd_calc"]: if trailing[0:len(cmd)] == cmd and ( len(trailing) == len(cmd) or (trailing[len(cmd):len(cmd)+1] in [" ", "="])): commandFound=cmd foundCalc=True if foundCalc: calcCmd = trailing[len(cmd)-1:].strip() if "=" in calcCmd[1:]: " Add a new calc " calcWord, calcDefinition = calcCmd.split("=", 1) calcWord = calcWord.strip() calcDefinition = calcDefinition.strip() if self.config["allowDelete"] and calcDefinition == "": result = self.deleteCalc(args[0], calcWord) if result: self.bot.act_PRIVMSG(args[0], "Calc deleted, %s." % sender.nick) else: self.bot.act_PRIVMSG(args[0], "Sorry %s, I don't know what '%s' is." % (sender.nick, calcWord)) else: if self.config["delaySubmit"]>0 and self.timeSince(args[0], "add") < self.config["delaySubmit"]: self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delaySubmit"], self.timeSince(args[0], "add"))) else: self.addNewCalc(args[0], calcWord, calcDefinition, prefix) self.bot.act_PRIVMSG(args[0], "Thanks for the info, %s." % sender.nick) self.updateTimeSince(args[0], "add") elif len(calcCmd)>0: " Lookup the word in calcCmd " if self.config["delayCalcSpecific"]>0 and self.timeSince(args[0], "calcspec") < self.config["delayCalcSpecific"]: self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalcSpecific"], self.timeSince(args[0], "calcspec"))) else: randCalc = self.getSpecificCalc(args[0], calcCmd) if randCalc==None: self.bot.act_PRIVMSG(args[0], "Sorry %s, I don't know what '%s' is." % (sender.nick, calcCmd)) else: self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"], randCalc["definition"], randCalc["by"])) self.updateTimeSince(args[0], "calcspec") else: if self.config["delayCalc"]>0 and self.timeSince(args[0], "calc") < self.config["delayCalc"]: self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalc"], self.timeSince(args[0], "calc"))) else: randCalc = self.getRandomCalc(args[0]) if randCalc == None: self.bot.act_PRIVMSG(args[0], "This channel has no calcs, %s :(" % (sender.nick,)) else: self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"], randCalc["definition"], randCalc["by"])) self.updateTimeSince(args[0], "calc") return cmd = self.bot.messageHasCommand(self.config["cmd_match"], trailing, True) if cmd: if self.config["delayMatch"]>0 and self.timeSince(args[0], "match") < self.config["delayMatch"]: self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayMatch"], self.timeSince(args[0], "match"))) else: term = cmd.args_str if term.strip()=='': return c = self.sql.getCursor() channelId = self.getChannelId(args[0]) c.execute("SELECT * FROM `calc_words` WHERE `word` LIKE ? AND `channel`=? ORDER BY `word` ASC ;", ("%%"+term+"%%", channelId)) rows = c.fetchall() if len(rows)==0: self.bot.act_PRIVMSG(args[0], "%s: Sorry, no matches" % sender.nick) else: matches = [] for row in rows[0:10]: if row == None: break matches.append(row["word"]) self.bot.act_PRIVMSG(args[0], "%s: %s match%s (%s\x03)" % (sender.nick, len(matches), "es" if len(matches)>1 else "", ", \x03".join(matches) )) self.updateTimeSince(args[0], "match") def addNewCalc(self, channel, word, definition, prefix): sender = self.bot.decodePrefix(prefix) " Find the channel ID" channelId = self.getChannelId(channel) " Check if we need to add a user" c = self.sql.getCursor() name = sender.nick host = sender.hostname c.execute("SELECT * FROM `calc_addedby` WHERE `username`=? AND `userhost`=? ;", (name, host)) rows = c.fetchall() if len(rows)==0: c.execute("INSERT INTO `calc_addedby` (`username`, `userhost`) VALUES (?, ?) ;", (name, host,)) c.execute("SELECT * FROM `calc_addedby` WHERE `username`=? AND `userhost`=? ;", (name, host)) rows = c.fetchall() addedId = rows[0]["id"] " Check if the word exists" c.execute("SELECT * FROM `calc_words` WHERE `channel`=? AND `word`=? ;", (channelId, word)) rows = c.fetchall() if len(rows)==0: c.execute("INSERT INTO `calc_words` (`channel`, `word`, `status`) VALUES (?, ?, ?) ;", (channelId, word, 'approved')) c.execute("SELECT * FROM `calc_words` WHERE `channel`=? AND `word`=? ;", (channelId, word)) rows = c.fetchall() wordId = rows[0]["id"] " Add definition " c.execute("INSERT INTO `calc_definitions` (`word`, `definition`, `addedby`, `date`, `status`) VALUES (?, ?, ?, ?, ?) ;", (wordId, definition, addedId, datetime.datetime.now(), 'approved',)) c.close() pass def getSpecificCalc(self, channel, word): c = self.sql.getCursor() channelId = self.getChannelId(channel) c.execute("SELECT `cw`.`word`, (SELECT `cdq`.`id` FROM `calc_definitions` `cdq` WHERE `cdq`.`word`=`cw`.`id` AND `cdq`.`status`='approved' ORDER BY `cdq`.`date` DESC LIMIT 1) as `definitionId` FROM `calc_words` `cw` WHERE `cw`.`channel`=? AND `cw`.`status`='approved' AND `cw`.`word`=? COLLATE NOCASE ORDER BY RANDOM() LIMIT 1 ;", (channelId, word.lower())) word = c.fetchone() if word == None: return None c.execute("SELECT `ca`.`username`, `cd`.`definition` FROM `calc_definitions` `cd` JOIN `calc_addedby` `ca` ON `ca`.`id` = `cd`.`addedby` WHERE `cd`.`id`=? LIMIT 1 ;", (word["definitionId"], )) who = c.fetchone() if who == None: return None c.close() return {"word":word["word"], "definition":who["definition"], "by":who["username"]} def getRandomCalc(self, channel): c = self.sql.getCursor() channelId = self.getChannelId(channel) for i in range(0, 5): c.execute("SELECT `cw`.`word`, (SELECT `cdq`.`id` FROM `calc_definitions` `cdq` WHERE `cdq`.`word`=`cw`.`id` AND `cdq`.`status`='approved' ORDER BY `cdq`.`date` DESC LIMIT 1) as `definitionId` FROM `calc_words` `cw` WHERE `cw`.`channel`=? AND `cw`.`status`='approved' ORDER BY RANDOM() LIMIT 1 ;", (channelId,)) word = c.fetchone() if word == None: return None c.execute("SELECT `ca`.`username`, `cd`.`definition` FROM `calc_definitions` `cd` JOIN `calc_addedby` `ca` ON `ca`.`id` = `cd`.`addedby` WHERE `cd`.`id`=? LIMIT 1 ;", (word["definitionId"], )) who = c.fetchone() if who == None: continue c.close() return {"word":word["word"], "definition":who["definition"], "by":who["username"]} def deleteCalc(self, channel, word): " Return true if deleted something, false if it doesnt exist" c = self.sql.getCursor() channelId = self.getChannelId(channel) c.execute("SELECT * FROM `calc_words` WHERE `channel`=? and `word`=? ;", (channelId, word)) rows = c.fetchall() if len(rows)==0: c.close() return False wordId = rows[0]["id"] #c.execute("DELETE FROM `calc_words` WHERE `id`=? ;", (wordId,)) #c.execute("DELETE FROM `calc_definitions` WHERE `word`=? ;", (wordId,)) c.execute("UPDATE `calc_definitions` SET `status`='deleted' WHERE `word`=? ;", (wordId,)) c.close() return True def getChannelId(self, channel): c = self.sql.getCursor() c.execute("SELECT * FROM `calc_channels` WHERE `channel` = ?", (channel,)) rows = c.fetchall() if len(rows)==0: c.execute("INSERT INTO `calc_channels` (`channel`) VALUES (?);", (channel,)) c.execute("SELECT * FROM `calc_channels` WHERE `channel` = ?", (channel,)) rows = c.fetchall() chId = rows[0]["id"] c.close() return chId