dispatch: port to django REST framework

this moves the dispatcher functionality that used to be in the old
ircbot directly to django REST framework, which is more robust and
allows for cooler stuff down the road. this still retains the ability to
have the bot privmsg, that still happens over the XML-RPC interface,
this is just a more convenient frontend to that
This commit is contained in:
Brian S. Stephan 2015-06-18 23:57:43 -05:00
parent fccb5f3fb3
commit 0641e1c062
11 changed files with 177 additions and 1 deletions

View File

View File

@ -0,0 +1,8 @@
"""Manage dispatch models in the admin interface."""
from django.contrib import admin
from dispatch.models import Dispatcher
admin.site.register(Dispatcher)

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Dispatcher',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('key', models.CharField(unique=True, max_length=16)),
('type', models.CharField(max_length=16, choices=[(b'privmsg', b'IRC privmsg'), (b'file', b'Write to file')])),
('destination', models.CharField(max_length=200)),
],
),
]

View File

View File

@ -0,0 +1,30 @@
"""Track dispatcher configurations."""
import logging
from django.db import models
log = logging.getLogger('dispatch.models')
class Dispatcher(models.Model):
"""Handle incoming API requests and do something with them."""
PRIVMSG_TYPE = 'privmsg'
FILE_TYPE = 'file'
TYPE_CHOICES = (
(PRIVMSG_TYPE, "IRC privmsg"),
(FILE_TYPE, "Write to file"),
)
key = models.CharField(max_length=16, unique=True)
type = models.CharField(max_length=16, choices=TYPE_CHOICES)
destination = models.CharField(max_length=200)
def __unicode__(self):
"""String representation."""
return u"{0:s} -> {1:s}".format(self.key, self.destination)

View File

@ -0,0 +1,17 @@
"""Serializers for the dispatcher API objects."""
from rest_framework import serializers
from dispatch.models import Dispatcher
class DispatcherSerializer(serializers.ModelSerializer):
class Meta:
model = Dispatcher
fields = ('id', 'key', 'type', 'destination')
class DispatchMessageSerializer(serializers.Serializer):
message = serializers.CharField()

12
dr_botzo/dispatch/urls.py Normal file
View File

@ -0,0 +1,12 @@
"""URL patterns for the dispatcher API."""
from django.conf.urls import patterns, url
from dispatch.views import DispatchMessage, DispatcherList, DispatcherDetail
urlpatterns = patterns('dispatch.views',
url(r'^api/dispatchers/$', DispatcherList.as_view(), name='dispatch_api_dispatchers'),
url(r'^api/dispatchers/(?P<pk>[0-9]+)/$', DispatcherDetail.as_view(), name='dispatch_api_dispatcher_detail'),
url(r'^api/dispatchers/(?P<pk>[0-9]+)/message$', DispatchMessage.as_view(), name='dispatch_api_dispatch_message'),
)

View File

@ -0,0 +1,72 @@
"""Handle dispatcher API requests."""
from __future__ import unicode_literals
import logging
import os
import xmlrpclib
from django.conf import settings
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import generics, status
from dispatch.models import Dispatcher
from dispatch.serializers import DispatchMessageSerializer, DispatcherSerializer
log = logging.getLogger('dispatch.views')
class DispatcherList(generics.ListAPIView):
"""List all dispatchers."""
queryset = Dispatcher.objects.all()
serializer_class = DispatcherSerializer
class DispatcherDetail(generics.RetrieveAPIView):
"""Detail the given dispatcher."""
queryset = Dispatcher.objects.all()
serializer_class = DispatcherSerializer
class DispatchMessage(APIView):
"""Send a message to the given dispatcher."""
queryset = Dispatcher.objects.none()
def get_object(self, pk):
try:
return Dispatcher.objects.get(pk=pk)
except Dispatcher.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
dispatcher = self.get_object(pk)
return Response({'message': ""})
def post(self, request, pk, format=None):
dispatcher = self.get_object(pk)
serializer = DispatchMessageSerializer(data=request.data)
if serializer.is_valid():
if dispatcher.type == Dispatcher.PRIVMSG_TYPE:
bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT)
bot = xmlrpclib.ServerProxy(bot_url)
log.debug("sending '%s' to channel %s", serializer.data['message'], dispatcher.destination)
bot.privmsg(dispatcher.destination, serializer.data['message'])
return Response({'status': "OK"})
elif dispatcher.type == Dispatcher.FILE_TYPE:
filename = os.path.abspath(dispatcher.destination)
log.debug("sending '%s' to file %s", serializer.data['message'], filename)
with open(filename, 'w') as f:
f.write(serializer.data['message'])
f.write('\n')
return Response({'status': "OK"})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

View File

@ -37,7 +37,9 @@ INSTALLED_APPS = (
'django.contrib.staticfiles',
'django_extensions',
'adminplus',
'rest_framework',
'countdown',
'dispatch',
'facts',
'ircbot',
'karma',
@ -121,6 +123,15 @@ STATICFILES_DIRS = (
)
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
# IRC bot stuff
# tuple of hostname, port number, and password (or None)

View File

@ -9,6 +9,7 @@ admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', 'dr_botzo.views.home', name='home'),
url(r'^dispatch/', include('dispatch.urls')),
url(r'^markov/', include('markov.urls')),
url(r'^races/', include('races.urls')),

View File

@ -1,5 +1,8 @@
Django==1.8.1
django-adminplus==0.3
django-extensions==1.5.3
django-filter==0.10.0
djangorestframework==3.1.3
httplib2==0.7.4
inflect==0.2.5
irc==12.1.4
@ -13,6 +16,7 @@ jaraco.logging==1.2
jaraco.text==1.3
logilab-astng==0.24.0
logilab-common==0.58.1
Markdown==2.6.2
more-itertools==2.2
MySQL-python==1.2.3
oauth2==1.5.211
@ -29,4 +33,3 @@ tempora==1.3
twython==3.0.0
yg.lockfile==2.0
zc.lockfile==1.1.0
django-adminplus==0.3