dr.botzo/karma/ircplugin.py

185 lines
8.7 KiB
Python
Raw Normal View History

"""Karma hooks for the IRC bot."""
import logging
import re
import irc.client
2015-06-20 16:34:18 -05:00
from django.conf import settings
2021-04-24 12:58:03 -05:00
from django.db.models import Count, Sum
2015-06-20 16:34:18 -05:00
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)
2021-04-24 12:58:03 -05:00
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'],
(r'^!karma\s+keyreport\s+(.*)'),
self.handle_keyreport, -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)
2021-04-24 12:58:03 -05:00
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_keyreport)
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+|$)'
2015-06-20 16:34:18 -05:00
where = event.target
if where in settings.KARMA_IGNORE_CHATTER_TARGETS:
2015-06-20 16:34:18 -05:00
log.debug("ignoring chatter in {0:s}".format(where))
return
# check the line for karma
2016-01-16 17:58:11 -06:00
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]
log.debug("key length: %d", len(key))
if len(key) > KarmaKey._meta.get_field('key').max_length:
log.warning("given a key longer than %d, ignoring", KarmaKey._meta.get_field('key').max_length)
return
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)))
2021-04-24 12:58:03 -05:00
def handle_keyreport(self, connection, event, match):
"""Provide report on a karma key."""
key = match.group(1).lower().rstrip()
try:
karma_key = KarmaKey.objects.get(key=key)
karmaers = KarmaLogEntry.objects.filter(key=karma_key)
karmaers = karmaers.values('nickmask').annotate(Sum('delta')).annotate(Count('delta')).order_by('-delta__count')
karmaers_list = [f"{irc.client.NickMask(x['nickmask']).nick} ({x['delta__count']}, {'+' if x['delta__sum'] >= 0 else ''}{x['delta__sum']})" for x in karmaers]
karmaers_list_str = ", ".join(karmaers_list[:10])
return self.bot.reply(event, f"most opinionated on {key}: {karmaers_list_str}")
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[:5]])
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[:5]])
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[:5]])
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