Add regex command hook to fix calc
This commit is contained in:
parent
9b225b87cc
commit
9b64dc3995
|
@ -3,14 +3,5 @@
|
||||||
"delaySubmit": 0,
|
"delaySubmit": 0,
|
||||||
"delayCalc": 0,
|
"delayCalc": 0,
|
||||||
"delayCalcSpecific": 0,
|
"delayCalcSpecific": 0,
|
||||||
"delayMatch": 0,
|
"delayMatch": 0
|
||||||
"cmd_calc": [
|
}
|
||||||
".calc",
|
|
||||||
"calc",
|
|
||||||
".quote"
|
|
||||||
],
|
|
||||||
"cmd_match": [
|
|
||||||
".match",
|
|
||||||
"match"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
from .pyircbot import PyIRCBot
|
from .pyircbot import PyIRCBot
|
||||||
from inspect import getargspec
|
from inspect import getargspec
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleBase:
|
class ModuleBase:
|
||||||
|
@ -156,6 +157,12 @@ class irchook(object):
|
||||||
getattr(func, ATTR_COMMAND_HOOK).extend(self)
|
getattr(func, ATTR_COMMAND_HOOK).extend(self)
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
def call(self, method, msg):
|
||||||
|
"""
|
||||||
|
Call the hooked function
|
||||||
|
"""
|
||||||
|
method(msg) # TODO is this actually a sane base?
|
||||||
|
|
||||||
def validate(self, msg, bot):
|
def validate(self, msg, bot):
|
||||||
"""
|
"""
|
||||||
Return True if the message should be passed on. False otherwise.
|
Return True if the message should be passed on. False otherwise.
|
||||||
|
@ -197,7 +204,7 @@ class command(irchook):
|
||||||
|
|
||||||
def call(self, method, msg):
|
def call(self, method, msg):
|
||||||
"""
|
"""
|
||||||
Internal use. Triggers the hooked function
|
Overridden to make the msg param optional
|
||||||
"""
|
"""
|
||||||
if len(getargspec(method).args) == 3:
|
if len(getargspec(method).args) == 3:
|
||||||
return method(self.parsed_cmd, msg)
|
return method(self.parsed_cmd, msg)
|
||||||
|
@ -227,3 +234,66 @@ class command(irchook):
|
||||||
self.parsed_cmd = cmd
|
self.parsed_cmd = cmd
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class regex(irchook):
|
||||||
|
"""
|
||||||
|
Decorator for calling module methods when a message matches a regex.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@regex(r'^foobar$')
|
||||||
|
def cmd_foobar(self, matches, msg):
|
||||||
|
print("Someone's message was exactly "foobar" ({}) in channel {}".format(msg.message, msg.args[0]))
|
||||||
|
|
||||||
|
This stores a list of IRC actions each function is tagged for in method.__tag_regexes. This attribute is scanned
|
||||||
|
during module init and appropriate hooks are set up.
|
||||||
|
|
||||||
|
:param regexps: expressions to match for
|
||||||
|
:type keywords: str
|
||||||
|
:param allow_private: enable matching in private messages
|
||||||
|
:type allow_private: bool
|
||||||
|
:param types: list of irc commands such as PRIVMSG to accept
|
||||||
|
:type types: list
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *regexps, allow_private=False, types=None):
|
||||||
|
self.regexps = [re.compile(r) for r in regexps]
|
||||||
|
self.allow_private = allow_private
|
||||||
|
self.matches = None
|
||||||
|
self.types = types
|
||||||
|
|
||||||
|
def call(self, method, msg):
|
||||||
|
"""
|
||||||
|
Overridden to pass matches and make an arg optional
|
||||||
|
"""
|
||||||
|
if len(getargspec(method).args) == 3:
|
||||||
|
return method(self.matches, msg)
|
||||||
|
else:
|
||||||
|
return method(self.matches)
|
||||||
|
|
||||||
|
def validate(self, msg, bot):
|
||||||
|
"""
|
||||||
|
Test a message and return true if matched.
|
||||||
|
|
||||||
|
:param msg: message to test against
|
||||||
|
:type msg: pyircbot.irccore.IRCEvent
|
||||||
|
:param bot: reference to main pyircbot
|
||||||
|
:type bot: pyircbot.pyircbot.PyIRCBot
|
||||||
|
"""
|
||||||
|
if self.types and msg.command not in self.types:
|
||||||
|
return False
|
||||||
|
if not self.allow_private and msg.args[0] == "#":
|
||||||
|
return False
|
||||||
|
for exp in self.regexps:
|
||||||
|
matches = exp.search(msg.trailing)
|
||||||
|
if matches:
|
||||||
|
self.matches = matches
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class MissingDependancyException(Exception):
|
||||||
|
"""
|
||||||
|
Exception expressing that a pyricbot module could not find a required module
|
||||||
|
"""
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
from pyircbot.modulebase import ModuleBase, ModuleHook, MissingDependancyException, regex, command
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
|
@ -9,13 +9,11 @@ class Calc(ModuleBase):
|
||||||
def __init__(self, bot, moduleName):
|
def __init__(self, bot, moduleName):
|
||||||
ModuleBase.__init__(self, bot, moduleName)
|
ModuleBase.__init__(self, bot, moduleName)
|
||||||
|
|
||||||
self.hooks = [ModuleHook("PRIVMSG", self.calc)]
|
|
||||||
self.timers = {}
|
self.timers = {}
|
||||||
|
|
||||||
self.sqlite = self.bot.getBestModuleForService("sqlite")
|
self.sqlite = self.bot.getBestModuleForService("sqlite")
|
||||||
if self.sqlite is None:
|
if self.sqlite is None:
|
||||||
self.log.error("Calc: SQLIite service is required.")
|
raise MissingDependancyException("Calc: SQLIite service is required.")
|
||||||
return
|
|
||||||
|
|
||||||
self.sql = self.sqlite.opendb("calc.db")
|
self.sql = self.sqlite.opendb("calc.db")
|
||||||
|
|
||||||
|
@ -81,105 +79,94 @@ class Calc(ModuleBase):
|
||||||
seconds = int(remaining - (minutes * 60))
|
seconds = int(remaining - (minutes * 60))
|
||||||
return "Please wait %s minute(s) and %s second(s)." % (minutes, seconds)
|
return "Please wait %s minute(s) and %s second(s)." % (minutes, seconds)
|
||||||
|
|
||||||
def calc(self, args, prefix, trailing):
|
# @regex(r'(?:^\.?(?:calc|quote)(?:\s+?(?:([^=]+)(?:\s?(=)\s?(.+)?)?)?)?)')
|
||||||
# Channel only
|
@regex(r'(?:^\.?(?:calc|quote)(?:\s+?(?:([^=]+)(?:\s?(=)\s?(.+)?)?)?)?)', types=['PRIVMSG'])
|
||||||
if not args[0][0] == "#":
|
def cmd_calc(self, match, message):
|
||||||
return
|
word, changeit, value = match.groups()
|
||||||
sender = self.bot.decodePrefix(prefix)
|
if word:
|
||||||
|
word = word.strip()
|
||||||
|
if value:
|
||||||
|
value = value.strip()
|
||||||
|
channel = message.args[0]
|
||||||
|
sender = message.prefix.nick
|
||||||
|
|
||||||
foundCalc = False
|
if word and changeit:
|
||||||
for cmd in self.config["cmd_calc"]:
|
# Add a new calc or delete
|
||||||
if trailing[0:len(cmd)] == cmd and (len(trailing) == len(cmd) or
|
if self.config["allowDelete"] and not value:
|
||||||
(trailing[len(cmd):len(cmd) + 1] in [" ", "="])):
|
result = self.deleteCalc(channel, word)
|
||||||
foundCalc = True
|
if result:
|
||||||
|
self.bot.act_PRIVMSG(channel, "Calc deleted, %s." % sender)
|
||||||
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:
|
else:
|
||||||
if self.config["delaySubmit"] > 0 and self.timeSince(args[0], "add") < self.config["delaySubmit"]:
|
self.bot.act_PRIVMSG(channel, "Sorry %s, I don't know what '%s' is." % (sender, word))
|
||||||
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 is 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:
|
else:
|
||||||
if self.config["delayCalc"] > 0 and self.timeSince(args[0], "calc") < self.config["delayCalc"]:
|
if self.config["delaySubmit"] > 0 and self.timeSince(channel, "add") < self.config["delaySubmit"]:
|
||||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalc"],
|
self.bot.act_PRIVMSG(channel, self.remainingToStr(self.config["delaySubmit"],
|
||||||
self.timeSince(args[0], "calc")))
|
self.timeSince(channel, "add")))
|
||||||
else:
|
else:
|
||||||
randCalc = self.getRandomCalc(args[0])
|
self.addNewCalc(channel, word, value, sender, message.prefix.hostname)
|
||||||
if randCalc is None:
|
self.bot.act_PRIVMSG(channel, "Thanks for the info, %s." % sender)
|
||||||
self.bot.act_PRIVMSG(args[0], "This channel has no calcs, %s :(" % (sender.nick,))
|
self.updateTimeSince(channel, "add")
|
||||||
else:
|
elif word:
|
||||||
self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"],
|
# Lookup the word in calc
|
||||||
randCalc["definition"], randCalc["by"]))
|
|
||||||
self.updateTimeSince(args[0], "calc")
|
|
||||||
return
|
|
||||||
|
|
||||||
cmd = self.bot.messageHasCommand(self.config["cmd_match"], trailing, True)
|
if self.config["delayCalcSpecific"] > 0 and \
|
||||||
if cmd:
|
self.timeSince(channel, "calcspec") < self.config["delayCalcSpecific"]:
|
||||||
if self.config["delayMatch"] > 0 and self.timeSince(args[0], "match") < self.config["delayMatch"]:
|
self.bot.act_PRIVMSG(sender, self.remainingToStr(self.config["delayCalcSpecific"],
|
||||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayMatch"],
|
self.timeSince(channel, "calcspec")))
|
||||||
self.timeSince(args[0], "match")))
|
|
||||||
else:
|
else:
|
||||||
term = cmd.args_str
|
randCalc = self.getSpecificCalc(channel, word)
|
||||||
if not term.strip():
|
if randCalc is None:
|
||||||
return
|
self.bot.act_PRIVMSG(channel, "Sorry %s, I don't know what '%s' is." % (sender, word))
|
||||||
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 not rows:
|
|
||||||
self.bot.act_PRIVMSG(args[0], "%s: Sorry, no matches" % sender.nick)
|
|
||||||
else:
|
else:
|
||||||
matches = []
|
self.bot.act_PRIVMSG(channel, "%s \x03= %s \x0314[added by: %s]" %
|
||||||
for row in rows[0:10]:
|
(randCalc["word"], randCalc["definition"], randCalc["by"]))
|
||||||
if not row:
|
self.updateTimeSince(channel, "calcspec")
|
||||||
break
|
else:
|
||||||
matches.append(row["word"])
|
if self.config["delayCalc"] > 0 and self.timeSince(channel, "calc") < self.config["delayCalc"]:
|
||||||
self.bot.act_PRIVMSG(args[0], "%s: %s match%s (%s\x03)" %
|
self.bot.act_PRIVMSG(sender, self.remainingToStr(self.config["delayCalc"],
|
||||||
(sender.nick, len(matches), "es" if len(matches) > 1 else
|
self.timeSince(channel, "calc")))
|
||||||
|
else:
|
||||||
|
randCalc = self.getRandomCalc(channel)
|
||||||
|
if randCalc is None:
|
||||||
|
self.bot.act_PRIVMSG(channel, "This channel has no calcs, %s :(" % (sender,))
|
||||||
|
else:
|
||||||
|
self.bot.act_PRIVMSG(channel, "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"],
|
||||||
|
randCalc["definition"], randCalc["by"]))
|
||||||
|
self.updateTimeSince(channel, "calc")
|
||||||
|
|
||||||
|
@command("match", require_args=True)
|
||||||
|
def cmd_match(self, cmd, msg):
|
||||||
|
if self.config["delayMatch"] > 0 and self.timeSince(msg.args[0], "match") < self.config["delayMatch"]:
|
||||||
|
self.bot.act_PRIVMSG(msg.prefix.nick, self.remainingToStr(self.config["delayMatch"],
|
||||||
|
self.timeSince(msg.args[0], "match")))
|
||||||
|
else:
|
||||||
|
term = cmd.args_str
|
||||||
|
if not term.strip():
|
||||||
|
return
|
||||||
|
c = self.sql.getCursor()
|
||||||
|
channelId = self.getChannelId(msg.args[0])
|
||||||
|
c.execute("SELECT * FROM `calc_words` WHERE `word` LIKE ? AND `channel`=? ORDER BY `word` ASC ;",
|
||||||
|
("%%" + term + "%%", channelId))
|
||||||
|
rows = c.fetchall()
|
||||||
|
if not rows:
|
||||||
|
self.bot.act_PRIVMSG(msg.args[0], "%s: Sorry, no matches" % msg.prefix.nick)
|
||||||
|
else:
|
||||||
|
matches = []
|
||||||
|
for row in rows[0:10]:
|
||||||
|
if not row:
|
||||||
|
break
|
||||||
|
matches.append(row["word"])
|
||||||
|
self.bot.act_PRIVMSG(msg.args[0], "%s: %s match%s (%s\x03)" %
|
||||||
|
(msg.prefix.nick, len(matches), "es" if len(matches) > 1 else
|
||||||
"", ", \x03".join(matches)))
|
"", ", \x03".join(matches)))
|
||||||
self.updateTimeSince(args[0], "match")
|
self.updateTimeSince(msg.args[0], "match")
|
||||||
|
|
||||||
def addNewCalc(self, channel, word, definition, prefix):
|
|
||||||
sender = self.bot.decodePrefix(prefix)
|
|
||||||
|
|
||||||
|
def addNewCalc(self, channel, word, definition, name, host):
|
||||||
" Find the channel ID"
|
" Find the channel ID"
|
||||||
channelId = self.getChannelId(channel)
|
channelId = self.getChannelId(channel)
|
||||||
|
|
||||||
" Check if we need to add a user"
|
" Check if we need to add a user"
|
||||||
c = self.sql.getCursor()
|
c = self.sql.getCursor()
|
||||||
name = sender.nick
|
|
||||||
host = sender.hostname
|
|
||||||
c.execute("SELECT * FROM `calc_addedby` WHERE `username`=? AND `userhost`=? ;", (name, host))
|
c.execute("SELECT * FROM `calc_addedby` WHERE `username`=? AND `userhost`=? ;", (name, host))
|
||||||
rows = c.fetchall()
|
rows = c.fetchall()
|
||||||
if not rows:
|
if not rows:
|
||||||
|
@ -201,7 +188,6 @@ class Calc(ModuleBase):
|
||||||
c.execute("INSERT INTO `calc_definitions` (`word`, `definition`, `addedby`, `date`, `status`) VALUES "
|
c.execute("INSERT INTO `calc_definitions` (`word`, `definition`, `addedby`, `date`, `status`) VALUES "
|
||||||
"(?, ?, ?, ?, ?) ;", (wordId, definition, addedId, datetime.datetime.now(), 'approved',))
|
"(?, ?, ?, ?, ?) ;", (wordId, definition, addedId, datetime.datetime.now(), 'approved',))
|
||||||
c.close()
|
c.close()
|
||||||
pass
|
|
||||||
|
|
||||||
def getSpecificCalc(self, channel, word):
|
def getSpecificCalc(self, channel, word):
|
||||||
c = self.sql.getCursor()
|
c = self.sql.getCursor()
|
||||||
|
|
Loading…
Reference in New Issue