collapsing all of dr_botzo one directory

This commit is contained in:
2017-02-04 11:48:55 -06:00
parent 38d14bb0d2
commit cd23f062a9
194 changed files with 0 additions and 0 deletions

0
ircbot/__init__.py Normal file
View File

41
ircbot/admin.py Normal file
View File

@@ -0,0 +1,41 @@
"""Manage ircbot models and admin actions in the admin interface."""
import logging
import xmlrpc.client
from django.conf import settings
from django.contrib import admin
from django.shortcuts import render
from ircbot.forms import PrivmsgForm
from ircbot.models import Alias, BotUser, IrcChannel, IrcPlugin
log = logging.getLogger('ircbot.admin')
admin.site.register(Alias)
admin.site.register(BotUser)
admin.site.register(IrcChannel)
admin.site.register(IrcPlugin)
def send_privmsg(request):
"""Send a privmsg over XML-RPC to the IRC bot."""
if request.method == 'POST':
form = PrivmsgForm(request.POST)
if form.is_valid():
target = form.cleaned_data['target']
message = form.cleaned_data['message']
bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT)
bot = xmlrpc.client.ServerProxy(bot_url)
bot.privmsg(target, message)
form = PrivmsgForm()
else:
form = PrivmsgForm()
return render(request, 'privmsg.html', {'form': form})
admin.site.register_view('ircbot/privmsg/', "Ircbot - privmsg", view=send_privmsg, urlname='ircbot_privmsg')

1105
ircbot/bot.py Normal file

File diff suppressed because it is too large Load Diff

15
ircbot/forms.py Normal file
View File

@@ -0,0 +1,15 @@
"""Forms for doing ircbot stuff."""
import logging
from django.forms import Form, CharField
log = logging.getLogger('markov.forms')
class PrivmsgForm(Form):
"""Accept a privmsg to send to the ircbot."""
target = CharField()
message = CharField()

View File

34
ircbot/ircplugins/echo.py Normal file
View File

@@ -0,0 +1,34 @@
import logging
from ircbot.lib import Plugin, reply_destination_for_event
log = logging.getLogger('ircbot.lib')
class Echo(Plugin):
"""Have IRC commands to do IRC things (join channels, quit, etc.)."""
def start(self):
"""Set up the handlers."""
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!echo\s+(.*)$',
self.handle_echo, -20)
super(Echo, self).start()
def stop(self):
"""Tear down handlers."""
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_echo)
super(Echo, self).stop()
def handle_echo(self, connection, event, match):
"""Handle the echo command... by echoing."""
return self.bot.reply(event, match.group(1))
plugin = Echo

View File

@@ -0,0 +1,66 @@
import logging
from ircbot.lib import Plugin, has_permission
from ircbot.models import IrcChannel
log = logging.getLogger('ircbot.ircplugins.ircmgmt')
class ChannelManagement(Plugin):
"""Have IRC commands to do IRC things (join channels, quit, etc.)."""
def start(self):
"""Set up the handlers."""
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!join\s+([\S]+)',
self.handle_join, -20)
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!part\s+([\S]+)',
self.handle_part, -20)
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!quit\s*(.*)',
self.handle_quit, -20)
super(ChannelManagement, self).start()
def stop(self):
"""Tear down handlers."""
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_join)
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_part)
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_quit)
super(ChannelManagement, self).stop()
def handle_join(self, connection, event, match):
"""Handle the join command."""
if has_permission(event.source, 'ircbot.manage_current_channels'):
channel = match.group(1)
# put it in the database if it isn't already
chan_mod, c = IrcChannel.objects.get_or_create(name=channel)
log.debug("joining channel %s", channel)
self.connection.join(channel)
return self.bot.reply(event, "Joined channel {0:s}.".format(channel))
def handle_part(self, connection, event, match):
"""Handle the join command."""
if has_permission(event.source, 'ircbot.manage_current_channels'):
channel = match.group(1)
# put it in the database if it isn't already
chan_mod, c = IrcChannel.objects.get_or_create(name=channel)
log.debug("parting channel %s", channel)
self.connection.part(channel)
return self.bot.reply(event, "Parted channel {0:s}.".format(channel))
def handle_quit(self, connection, event, match):
"""Handle the join command."""
if has_permission(event.source, 'ircbot.quit_bot'):
self.bot.die(msg=match.group(1))
plugin = ChannelManagement

View File

@@ -0,0 +1,48 @@
"""Watch channel topics for changes and note them."""
import logging
from django.utils import timezone
from ircbot.lib import Plugin
from ircbot.models import IrcChannel
log = logging.getLogger('ircbot.ircplugins.topicmonitor')
class TopicMonitor(Plugin):
"""Have IRC commands to do IRC things (join channels, quit, etc.)."""
def start(self):
"""Set up the handlers."""
self.connection.reactor.add_global_handler('topic', handle_topic, -20)
super(TopicMonitor, self).start()
def stop(self):
"""Tear down handlers."""
self.connection.reactor.remove_global_handler('topic', handle_topic)
super(TopicMonitor, self).stop()
def handle_topic(connection, event):
"""Store topic changes in the channel model."""
channel = event.target
topic = event.arguments[0]
setter = event.source
log.debug("topic change '%s' by %s in %s", topic, setter, channel)
channel, c = IrcChannel.objects.get_or_create(name=channel)
channel.topic_msg = topic
channel.topic_time = timezone.now()
channel.topic_by = setter
channel.save()
plugin = TopicMonitor

81
ircbot/lib.py Normal file
View File

@@ -0,0 +1,81 @@
"""Library and convenience methods for the IRC bot and plugins."""
import logging
import irc.client
from django.core.exceptions import ObjectDoesNotExist
from ircbot.models import BotUser
log = logging.getLogger('ircbot.lib')
class Plugin(object):
"""Plugin base class."""
def __init__(self, bot, connection, event):
"""Initialization stuff here --- global handlers, configs from database, so on."""
self.bot = bot
self.connection = connection
self.event = event
log.info("initialized %s", self.__class__.__name__)
def start(self):
"""Initialization stuff here --- global handlers, configs from database, so on."""
log.info("started %s", self.__class__.__name__)
def stop(self):
"""Teardown stuff here --- unregister handlers, for example."""
log.info("stopped %s", self.__class__.__name__)
def _unencode_xml(self, text):
"""Convert <, >, & to their real entities."""
text = text.replace('&lt;', '<')
text = text.replace('&gt;', '>')
text = text.replace('&amp;', '&')
return text
def has_permission(source, permission):
"""Check if the provided event source is a bot admin."""
try:
bot_user = BotUser.objects.get(nickmask=source)
log.debug("found bot user %s", bot_user)
except BotUser.DoesNotExist:
log.debug("could not find bot user for %s", source)
return False
try:
django_user = bot_user.user
if django_user.has_perm(permission):
log.debug("bot user %s has requested permission %s", bot_user, permission)
return True
except ObjectDoesNotExist:
log.error("could not find django user for bot user %s", bot_user)
return False
log.debug("bot user %s does not have requested permission %s", bot_user, permission)
return False
def reply_destination_for_event(event):
"""Get the "natural" reply destination for an event.
If the event appears to be from a person within a channel, the channel
is the reply destination. Otherwise, the source (assumed to be the speaker
in a privmsg)'s nick is the reply destination.
"""
if irc.client.is_channel(event.target):
return event.target
else:
return irc.client.NickMask(event.source).nick

View File

View File

View File

@@ -0,0 +1,27 @@
"""Start the IRC bot via Django management command."""
import logging
import signal
from django.core.management import BaseCommand
from ircbot.bot import IRCBot
log = logging.getLogger('ircbot')
class Command(BaseCommand):
"""Provide the command to start the IRC bot.
This will run until the bot disconnects and shuts down.
"""
help = "Start the IRC bot"
def handle(self, *args, **options):
"""Start the IRC bot and spin forever."""
irc = IRCBot()
signal.signal(signal.SIGINT, irc.sigint_handler)
irc.start()

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='IrcChannel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(unique=True, max_length=200)),
('autojoin', models.BooleanField(default=False)),
],
),
]

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='BotAdmin',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('nickmask', models.CharField(unique=True, max_length=200)),
],
),
migrations.CreateModel(
name='IrcPlugin',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('path', models.CharField(unique=True, max_length=200)),
('autojoin', models.BooleanField(default=False)),
],
),
]

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0002_botadmin_ircplugin'),
]
operations = [
migrations.RenameField(
model_name='ircplugin',
old_name='autojoin',
new_name='autoload',
),
]

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0003_auto_20150512_1934'),
]
operations = [
migrations.CreateModel(
name='Alias',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('pattern', models.CharField(unique=True, max_length=200)),
('replacement', models.CharField(max_length=200)),
],
),
]

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0004_alias'),
]
operations = [
migrations.AlterModelOptions(
name='alias',
options={'verbose_name_plural': 'aliases'},
),
]

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0005_auto_20150514_2317'),
]
operations = [
migrations.AddField(
model_name='ircchannel',
name='topic_by',
field=models.CharField(default=b'', max_length=200),
),
migrations.AddField(
model_name='ircchannel',
name='topic_msg',
field=models.TextField(default=b''),
),
migrations.AddField(
model_name='ircchannel',
name='topic_time',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0006_auto_20150515_2141'),
]
operations = [
migrations.AlterModelOptions(
name='ircplugin',
options={'ordering': ['path']},
),
]

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0007_auto_20150519_2156'),
]
operations = [
migrations.AlterField(
model_name='ircchannel',
name='topic_by',
field=models.CharField(default=b'', max_length=200, blank=True),
),
migrations.AlterField(
model_name='ircchannel',
name='topic_msg',
field=models.TextField(default=b'', blank=True),
),
]

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('ircbot', '0008_auto_20150521_2113'),
]
operations = [
migrations.AddField(
model_name='botadmin',
name='user',
field=models.ForeignKey(default=1, to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0009_botadmin_user'),
]
operations = [
migrations.RenameModel(
old_name='BotAdmin',
new_name='BotUser',
),
]

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0010_auto_20150620_0930'),
]
operations = [
migrations.AlterModelOptions(
name='botuser',
options={'permissions': (('quit_bot', 'Can tell the bot to quit via IRC'),)},
),
migrations.AlterModelOptions(
name='ircchannel',
options={'permissions': (('manage_current_channels', 'Can join/part channels via IRC'),)},
),
migrations.AlterModelOptions(
name='ircplugin',
options={'ordering': ['path'], 'permissions': (('manage_loaded_plugins', 'Can load/unload plugins via IRC'),)},
),
]

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0011_auto_20150620_0951'),
]
operations = [
migrations.AddField(
model_name='ircchannel',
name='markov_learn_from_channel',
field=models.BooleanField(default=True),
),
]

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from django.db import models, migrations
import ircbot.models
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0012_ircchannel_markov_learn_from_channel'),
]
operations = [
migrations.AlterField(
model_name='ircchannel',
name='name',
field=ircbot.models.LowerCaseCharField(unique=True, max_length=200),
),
]

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ircbot', '0013_auto_20150917_2255'),
]
operations = [
migrations.AlterField(
model_name='ircchannel',
name='topic_by',
field=models.CharField(default='', blank=True, max_length=200),
),
migrations.AlterField(
model_name='ircchannel',
name='topic_msg',
field=models.TextField(default='', blank=True),
),
]

View File

103
ircbot/models.py Normal file
View File

@@ -0,0 +1,103 @@
"""Track basic IRC settings and similar."""
import logging
import re
from django.conf import settings
from django.db import models
from django.utils import timezone
log = logging.getLogger('ircbot.models')
class LowerCaseCharField(models.CharField):
def get_prep_value(self, value):
value = super(LowerCaseCharField, self).get_prep_value(value)
if value is not None:
value = value.lower()
return value
class Alias(models.Model):
"""Allow for aliasing of arbitrary regexes to normal supported commands."""
pattern = models.CharField(max_length=200, unique=True)
replacement = models.CharField(max_length=200)
class Meta:
verbose_name_plural = "aliases"
def __str__(self):
"""String representation."""
return "{0:s} -> {1:s}".format(self.pattern, self.replacement)
def replace(self, what):
command = None
if re.search(self.pattern, what, flags=re.IGNORECASE):
command = re.sub(self.pattern, self.replacement, what, flags=re.IGNORECASE)
return command
class BotUser(models.Model):
"""Configure bot users, which can do things through the bot and standard Django auth."""
nickmask = models.CharField(max_length=200, unique=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Meta:
permissions = (
('quit_bot', "Can tell the bot to quit via IRC"),
)
def __str__(self):
"""String representation."""
return "{0:s} (Django user {1:s})".format(self.nickmask, self.user.username)
class IrcChannel(models.Model):
"""Track channel settings."""
name = LowerCaseCharField(max_length=200, unique=True)
autojoin = models.BooleanField(default=False)
topic_msg = models.TextField(default='', blank=True)
topic_time = models.DateTimeField(default=timezone.now)
topic_by = models.CharField(max_length=200, default='', blank=True)
markov_learn_from_channel = models.BooleanField(default=True)
class Meta:
permissions = (
('manage_current_channels', "Can join/part channels via IRC"),
)
def __str__(self):
"""String representation."""
return "{0:s}".format(self.name)
class IrcPlugin(models.Model):
"""Represent an IRC plugin and its loading settings."""
path = models.CharField(max_length=200, unique=True)
autoload = models.BooleanField(default=False)
class Meta:
ordering = ['path']
permissions = (
('manage_loaded_plugins', "Can load/unload plugins via IRC"),
)
def __str__(self):
"""String representation."""
return "{0:s}".format(self.path)

View File

@@ -0,0 +1,15 @@
{% extends 'adminplus/index.html' %}
{% block title %}Ircbot - Privmsg{% endblock %}
{% block content %}
<div id="content-main">
<form id="ircbot_privmsg_form" action="{% url 'admin:ircbot_privmsg' %}" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input class="submit-button" type="submit" value="Privmsg"/>
</form>
</div>
{% endblock %}