"""Karma hooks for the IRC bot.""" import logging import re import irc.client from django.conf import settings from ircbot.lib import Plugin from karma.models import KarmaKey, KarmaLogEntry log = logging.getLogger('karma.ircplugin') class Karma(Plugin): """Track karma and report on it.""" def start(self): """Set up the handlers.""" self.connection.add_global_handler('pubmsg', self.handle_chatter, -20) self.connection.add_global_handler('privmsg', self.handle_chatter, -20) self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!karma\s+rank\s+(.*)$', self.handle_rank, -20) self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], (r'^!karma\s+report\s+(highest|lowest|positive|negative' r'|top|opinionated)'), self.handle_report, -20) self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!karma\s+stats\s+([\S]+)', self.handle_stats, -20) super(Karma, self).start() def stop(self): """Tear down handlers.""" self.connection.remove_global_handler('pubmsg', self.handle_chatter) self.connection.remove_global_handler('privmsg', self.handle_chatter) self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_rank) self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_report) self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_stats) super(Karma, self).stop() @staticmethod def handle_chatter(connection, event): """Watch karma from IRC chatter.""" what = event.arguments[0].lower() karma_pattern = r'(?:\((.+?)\)|(\S+))(\+\+|--|\+-|-\+)(\s+|$)' where = event.target if where in settings.KARMA_IGNORE_CHATTER_TARGETS: log.debug("ignoring chatter in {0:s}".format(where)) return # check the line for karma log.debug("searching '%s' for karma", what) matches = re.findall(karma_pattern, what, re.IGNORECASE) for match in matches: key = match[0] if match[0] else match[1] value = match[2] karma_key, c = KarmaKey.objects.get_or_create(key=key) if value == '++': KarmaLogEntry.objects.create(key=karma_key, delta=1, nickmask=event.source) elif value == '--': KarmaLogEntry.objects.create(key=karma_key, delta=-1, nickmask=event.source) elif value == '+-': KarmaLogEntry.objects.create(key=karma_key, delta=1, nickmask=event.source) KarmaLogEntry.objects.create(key=karma_key, delta=-1, nickmask=event.source) elif value == '-+': KarmaLogEntry.objects.create(key=karma_key, delta=-1, nickmask=event.source) KarmaLogEntry.objects.create(key=karma_key, delta=1, nickmask=event.source) def handle_rank(self, connection, event, match): """Report on the rank of a karma item.""" where = event.target if where in settings.KARMA_IGNORE_COMMAND_TARGETS: log.debug("ignoring command in {0:s}".format(where)) return key = match.group(1).lower().rstrip() try: karma_key = KarmaKey.objects.get(key=key) return self.bot.reply(event, "{0:s} has {1:d} points of karma (rank {2:d})".format(karma_key.key, karma_key.score(), karma_key.rank())) except KarmaKey.DoesNotExist: return self.bot.reply(event, "i have not seen any karma for {0:s}".format(match.group(1))) def handle_report(self, connection, event, match): """Provide some karma reports.""" where = event.target if where in settings.KARMA_IGNORE_COMMAND_TARGETS: log.debug("ignoring command in {0:s}".format(where)) return report = match.group(1).lower() if report == 'highest': sorted_keys = KarmaKey.objects.ranked_scored_order() msg = "top 5 recipients: {0:s}".format(", ".join([str(x) for x in sorted_keys[:5]])) return self.bot.reply(event, msg) elif report == 'lowest': sorted_keys = KarmaKey.objects.ranked_scored_reverse_order() msg = "bottom 5 recipients: {0:s}".format(", ".join([str(x) for x in sorted_keys[:5]])) return self.bot.reply(event, msg) elif report == 'positive': karmaers = KarmaLogEntry.objects.optimists() karmaer_list = ", ".join(["{0:s} ({1:d})".format(irc.client.NickMask(x['nickmask']).nick, x['karma_outlook']) for x in karmaers]) msg = "top 5 optimists: {0:s}".format(karmaer_list) return self.bot.reply(event, msg) elif report == 'negative': karmaers = KarmaLogEntry.objects.pessimists() karmaer_list = ", ".join(["{0:s} ({1:d})".format(irc.client.NickMask(x['nickmask']).nick, x['karma_outlook']) for x in karmaers]) msg = "top 5 pessimists: {0:s}".format(karmaer_list) return self.bot.reply(event, msg) elif report == 'top' or report == 'opinionated': karmaers = KarmaLogEntry.objects.most_opinionated() karmaer_list = ", ".join(["{0:s} ({1:d})".format(irc.client.NickMask(x['nickmask']).nick, x['karma_count']) for x in karmaers]) msg = "top 5 opinionated users: {0:s}".format(karmaer_list) return self.bot.reply(event, msg) def handle_stats(self, connection, event, match): """Provide stats on a karma user.""" where = event.target if where in settings.KARMA_IGNORE_COMMAND_TARGETS: log.debug("ignoring command in {0:s}".format(where)) return karmaer = match.group(1) log_entries = KarmaLogEntry.objects.filter(nickmask=karmaer) if len(log_entries) == 0: # fallback, try to match the nick part of nickmask log_entries = KarmaLogEntry.objects.filter(nickmask__startswith='{0:s}!'.format(karmaer)) if len(log_entries) == 0: return self.bot.reply(event, "karma user {0:s} not found".format(karmaer)) total_karma = log_entries.count() positive_karma = log_entries.filter(delta__gt=0).count() negative_karma = log_entries.filter(delta__lt=0).count() msg = ("{0:s} has given {1:d} postive karma and {2:d} negative karma, for a total of {3:d} karma" "".format(karmaer, positive_karma, negative_karma, total_karma)) return self.bot.reply(event, msg) plugin = Karma