start work switch to py3 and ircbot

This commit is contained in:
Thomas Steen Rasmussen 2017-01-30 12:05:11 +01:00
parent 12e6c0374e
commit 6eefcdda74
17 changed files with 222 additions and 15 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ db.sqlite3
.env .env
*.pyc *.pyc
venv/ venv/
venv3/

View file

@ -44,6 +44,7 @@ INSTALLED_APPS = [
'program', 'program',
'info', 'info',
'sponsors', 'sponsors',
'ircbot',
'allauth', 'allauth',
'allauth.account', 'allauth.account',

0
ircbot/__init__.py Normal file
View file

3
ircbot/admin.py Normal file
View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

7
ircbot/apps.py Normal file
View file

@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class IrcbotConfig(AppConfig):
name = 'ircbot'

91
ircbot/irc3module.py Normal file
View file

@ -0,0 +1,91 @@
import irc3
from ircbot.models import OutgoingIrcMessage
from django.conf import settings
@irc3.plugin
class Plugin(object):
"""BornHack IRC3 class"""
requires = [
'irc3.plugins.core', # makes the bot able to connect to an irc server and do basic irc stuff
'irc3.plugins.userlist', # maintains a convenient list of the channels the bot is in and their users
'irc3.plugins.command', # what does this do?
]
def __init__(self, bot):
self.bot = bot
self.log = self.bot.log
###############################################################################################
### builtin irc3 event methods
def server_ready(self, **kwargs):
"""triggered after the server sent the MOTD (require core plugin)"""
if settings.DEBUG:
print("inside server_ready(), kwargs: %s" % kwargs)
def connection_lost(self, **kwargs):
"""triggered when connection is lost"""
if settings.DEBUG:
print("inside connection_lost(), kwargs: %s" % kwargs)
def connection_made(self, **kwargs):
"""triggered when connection is up"""
if settings.DEBUG:
print("inside connection_made(), kwargs: %s" % kwargs)
###############################################################################################
### decorated irc3 event methods
@irc3.event(irc3.rfc.JOIN_PART_QUIT)
def on_join_part_quit(self, **kwargs):
"""triggered when there is a join part or quit on a channel the bot is in"""
if settings.DEBUG:
print("inside on_join_part_quit(), kwargs: %s" % kwargs)
if self.bot.nick == kwargs['mask'].split("!")[0] and kwargs['channel'] == "#tirsdagsfilm":
self.bot.loop.call_later(1, self.bot.get_outgoing_messages)
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg(self, **kwargs):
"""triggered when a privmsg is sent to the bot or to a channel the bot is in"""
if settings.DEBUG:
print("inside on_privmsg(), kwargs: %s" % kwargs)
@irc3.event(irc3.rfc.KICK)
def on_kick(self, **kwargs):
if settings.DEBUG:
print("inside on_kick(), kwargs: %s" % kwargs)
###############################################################################################
### custom irc3 methods
@irc3.extend
def get_outgoing_messages(self):
"""
This method gets unprocessed OutgoingIrcMessage objects and attempts to send them to
the target channel. Messages are skipped if the bot is not in the channel.
"""
# TODO: handle privmsg to users
# TODO: set a timeout for messages.. a few minutes maybe?
# TODO: make sleep time configurable
print("inside get_outgoing_messages()")
for msg in OutgoingIrcMessage.objects.filter(processed=False).order_by('created_date'):
if msg.target[0] == "#" and msg.target in self.bot.channels:
print("sending privmsg to %s: %s" % (msg.target, msg.message))
self.bot.privmsg(msg.target, msg.message)
msg.processed=True
msg.save()
else:
print("skipping message to channel %s because the bot is not in the channel" % msg.target)
# call this function again in 60 seconds
self.bot.loop.call_later(60, self.bot.get_outgoing_messages)

View file

View file

View file

@ -0,0 +1,30 @@
from django.core.management.base import BaseCommand
from django.conf import settings
from django.utils import timezone
from time import sleep
import irc3, sys, asyncio
class Command(BaseCommand):
args = 'none'
help = 'Runs the BornHack IRC bot to announce talks and manage team channel permissions'
def output(self, message):
self.stdout.write('%s: %s' % (timezone.now().strftime("%Y-%m-%d %H:%M:%S"), message))
def handle(self, *args, **options):
self.output('IRC bot worker running...')
# connect to IRC
config = {
'nick': 'BornHack',
'autojoins': ['#tirsdagsfilm'],
'host': 'ircd.tyknet.dk',
'port': 6697,
'ssl': True,
'timeout': 30,
'includes': [
'ircbot.irc3module',
],
}
irc3.IrcBot(**config).run(forever=True)

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-01-29 20:29
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='OutgoingIrcMessage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('updated', models.DateTimeField(auto_now=True)),
('target', models.CharField(max_length=100)),
('message', models.CharField(max_length=200)),
('processed', models.BooleanField(default=False)),
],
options={
'abstract': False,
},
),
]

View file

10
ircbot/models.py Normal file
View file

@ -0,0 +1,10 @@
from __future__ import unicode_literals
from utils.models import UUIDModel, CreatedUpdatedModel
from django.db import models
class OutgoingIrcMessage(CreatedUpdatedModel):
target = models.CharField(max_length=100)
message = models.CharField(max_length=200)
processed = models.BooleanField(default=False)

3
ircbot/views.py Normal file
View file

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View file

@ -4,6 +4,7 @@ Pillow==4.0.0
PyPDF2==1.26.0 PyPDF2==1.26.0
Unidecode==0.04.20 Unidecode==0.04.20
argparse==1.2.1 argparse==1.2.1
asyncio==3.4.3
bleach==1.5.0 bleach==1.5.0
django-allauth==0.30.0 django-allauth==0.30.0
django-bleach==0.3.0 django-bleach==0.3.0
@ -11,8 +12,10 @@ django-bootstrap3==8.1.0
django-debug-toolbar==1.6 django-debug-toolbar==1.6
django-environ==0.4.1 django-environ==0.4.1
django-wkhtmltopdf==3.1.0 django-wkhtmltopdf==3.1.0
docopt==0.6.2
future==0.16.0 future==0.16.0
html5lib==0.9999999 html5lib==0.9999999
irc3==0.9.8
oauthlib==2.0.1 oauthlib==2.0.1
olefile==0.44 olefile==0.44
psycopg2==2.6.2 psycopg2==2.6.2
@ -23,5 +26,6 @@ requests==2.12.5
requests-oauthlib==0.7.0 requests-oauthlib==0.7.0
six==1.10.0 six==1.10.0
sqlparse==0.2.2 sqlparse==0.2.2
venusian==1.0
webencodings==0.5 webencodings==0.5
wsgiref==0.1.2 wsgiref==0.1.2

30
requirements3.txt Normal file
View file

@ -0,0 +1,30 @@
CommonMark==0.7.3
Django==1.10.5
Pillow==4.0.0
PyPDF2==1.26.0
Unidecode==0.04.20
argparse==1.2.1
asyncio==3.4.3
bleach==1.5.0
django-allauth==0.30.0
django-bleach==0.3.0
django-bootstrap3==8.1.0
django-debug-toolbar==1.6
django-environ==0.4.1
django-wkhtmltopdf==3.1.0
docopt==0.6.2
future==0.16.0
html5lib==0.9999999
irc3==0.9.8
oauthlib==2.0.1
olefile==0.44
psycopg2==2.6.2
python-openid==2.2.5
pytz==2016.10
qrcode==5.3
requests==2.12.5
requests-oauthlib==0.7.0
six==1.10.0
sqlparse==0.2.2
venusian==1.0
webencodings==0.5

View file

@ -1,5 +1,5 @@
from django.conf.urls import url from django.conf.urls import url
from views import * from .views import *
urlpatterns = [ urlpatterns = [
url(r'^$', ShopIndexView.as_view(), name='index'), url(r'^$', ShopIndexView.as_view(), name='index'),

View file

@ -447,21 +447,18 @@ class EpayCallbackView(SingleObjectMixin, View):
if 'orderid' in request.GET: if 'orderid' in request.GET:
query = OrderedDict( query = OrderedDict(
map( [tuple(x.split('=')) for x in request.META['QUERY_STRING'].split('&')]
lambda x: tuple(x.split('=')),
request.META['QUERY_STRING'].split('&')
)
) )
order = get_object_or_404(Order, pk=query.get('orderid')) order = get_object_or_404(Order, pk=query.get('orderid'))
if order.pk != self.get_object().pk: if order.pk != self.get_object().pk:
print "bad epay callback, orders do not match!" print("bad epay callback, orders do not match!")
return HttpResponse(status=400) return HttpResponse(status=400)
if validate_epay_callback(query): if validate_epay_callback(query):
callback.md5valid=True callback.md5valid=True
callback.save() callback.save()
else: else:
print "bad epay callback!" print("bad epay callback!")
return HttpResponse(status=400) return HttpResponse(status=400)
if order.paid: if order.paid:
@ -479,7 +476,7 @@ class EpayCallbackView(SingleObjectMixin, View):
### and mark order as paid (this will create tickets) ### and mark order as paid (this will create tickets)
order.mark_as_paid() order.mark_as_paid()
else: else:
print "valid epay callback with wrong amount detected" print("valid epay callback with wrong amount detected")
else: else:
return HttpResponse(status=400) return HttpResponse(status=400)
@ -541,7 +538,7 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
# check if it expired # check if it expired
if parse_datetime(order.coinifyapiinvoice.invoicejson['expire_time']) < timezone.now(): if parse_datetime(order.coinifyapiinvoice.invoicejson['expire_time']) < timezone.now():
# this coinifyinvoice expired, delete it # this coinifyinvoice expired, delete it
print "deleting expired coinifyinvoice id %s" % order.coinifyapiinvoice.invoicejson['id'] print("deleting expired coinifyinvoice id %s" % order.coinifyapiinvoice.invoicejson['id'])
order.coinifyapiinvoice.delete() order.coinifyapiinvoice.delete()
order = self.get_object() order = self.get_object()
@ -568,10 +565,10 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
# Parse response # Parse response
if not response['success']: if not response['success']:
api_error = response['error'] api_error = response['error']
print "API error: %s (%s)" % ( print("API error: %s (%s)" % (
api_error['message'], api_error['message'],
api_error['code'] api_error['code']
) ))
messages.error(request, "There was a problem with the payment provider. Please try again later") messages.error(request, "There was a problem with the payment provider. Please try again later")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})) return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
else: else:
@ -580,7 +577,7 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
invoicejson = response['data'], invoicejson = response['data'],
order = order, order = order,
) )
print "created new coinifyinvoice id %s" % coinifyinvoice.invoicejson['id'] print("created new coinifyinvoice id %s" % coinifyinvoice.invoicejson['id'])
return super(CoinifyRedirectView, self).dispatch( return super(CoinifyRedirectView, self).dispatch(
request, *args, **kwargs request, *args, **kwargs
) )
@ -603,7 +600,7 @@ class CoinifyCallbackView(SingleObjectMixin, View):
# make a dict with all HTTP_ headers # make a dict with all HTTP_ headers
headerdict = {} headerdict = {}
for key, value in request.META.iteritems(): for key, value in request.META.items():
if key[:5] == 'HTTP_': if key[:5] == 'HTTP_':
headerdict[key[5:]] = value headerdict[key[5:]] = value
@ -625,7 +622,7 @@ class CoinifyCallbackView(SingleObjectMixin, View):
try: try:
coinifyinvoice = CoinifyAPIInvoice.objects.get(invoicejson__id=callbackjson['data']['id']) coinifyinvoice = CoinifyAPIInvoice.objects.get(invoicejson__id=callbackjson['data']['id'])
except CoinifyAPIInvoice.DoesNotExist: except CoinifyAPIInvoice.DoesNotExist:
print "unable to find CoinifyAPIInvoice with id %s" % callbackjson['data']['id'] print("unable to find CoinifyAPIInvoice with id %s" % callbackjson['data']['id'])
return HttpResponseBadRequest('bad coinifyinvoice id') return HttpResponseBadRequest('bad coinifyinvoice id')
# save new coinifyinvoice payload # save new coinifyinvoice payload
@ -641,7 +638,7 @@ class CoinifyCallbackView(SingleObjectMixin, View):
else: else:
return HttpResponseBadRequest('unsupported event') return HttpResponseBadRequest('unsupported event')
else: else:
print "invalid coinify callback detected" print("invalid coinify callback detected")
return HttpResponseBadRequest('something is fucky') return HttpResponseBadRequest('something is fucky')