Compare commits

..

No commits in common. "f78d407d4cbfa6c5a17ba611c0ddb367b54e72ce" and "058993913747f62edfc1dea24a72d446a9770b2c" have entirely different histories.

39 changed files with 559 additions and 405 deletions

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-02-23 02:25 # Generated by Django 1.10.5 on 2017-02-23 02:25
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-02-24 01:06 # Generated by Django 1.10.5 on 2017-02-24 01:06
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-02-24 01:12 # Generated by Django 1.10.5 on 2017-02-24 01:12
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -1,28 +1,36 @@
"""Roll dice when asked, intended for RPGs.""" """Roll dice when asked, intended for RPGs."""
# this breaks yacc, but ply might be happy in py3
#from __future__ import unicode_literals
import logging import logging
import math
import re import re
import random import random
from irc.client import NickMask from irc.client import NickMask
from dice.roller import DiceRoller import ply.lex as lex
import ply.yacc as yacc
from ircbot.lib import Plugin from ircbot.lib import Plugin
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Dice(Plugin): class Dice(Plugin):
"""Roll simple or complex dice strings."""
def __init__(self): """Roll simple or complex dice strings."""
"""Set up the plugin."""
super(Dice, self).__init__()
self.roller = DiceRoller()
def start(self): def start(self):
"""Set up the handlers.""" """Set up the handlers."""
self.roller = DiceRoller()
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!roll\s+(.*)$', self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!roll\s+(.*)$',
self.handle_roll, -20) self.handle_roll, -20)
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!ctech\s+(.*)$',
self.handle_ctech, -20)
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!random\s+(.*)$', self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!random\s+(.*)$',
self.handle_random, -20) self.handle_random, -20)
@ -30,7 +38,9 @@ class Dice(Plugin):
def stop(self): def stop(self):
"""Tear down handlers.""" """Tear down handlers."""
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_roll) self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_roll)
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_ctech)
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_random) self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_random)
super(Dice, self).stop() super(Dice, self).stop()
@ -58,17 +68,368 @@ class Dice(Plugin):
dicestr = match.group(1) dicestr = match.group(1)
logger.debug(event.recursing) logger.debug(event.recursing)
try:
reply_str = self.roller.do_roll(dicestr)
except AssertionError as aex:
reply_str = f"Could not roll dice: {aex}"
except ValueError:
reply_str = "Unable to parse roll"
if event.recursing: if event.recursing:
reply = "{0:s}".format(reply_str) reply = "{0:s}".format(self.roller.do_roll(dicestr))
else: else:
reply = "{0:s}: {1:s}".format(nick, reply_str) reply = "{0:s}: {1:s}".format(nick, self.roller.do_roll(dicestr))
return self.bot.reply(event, re.sub(r'(\d+)(.*?\s+)(\(.*?\))', r'\1\214\3', reply)) return self.bot.reply(event, re.sub(r'(\d+)(.*?\s+)(\(.*?\))', r'\1\214\3', reply))
def handle_ctech(self, connection, event, match):
"""Handle cthulhutech dice rolls."""
nick = NickMask(event.source).nick
rollitrs = re.split(';\s*', match.group(1))
reply = ""
for count, roll in enumerate(rollitrs):
pattern = '^(\d+)d(?:(\+|\-)(\d+))?(?:\s+(.*))?'
regex = re.compile(pattern)
matches = regex.search(roll)
if matches is not None:
dice = int(matches.group(1))
modifier = 0
if matches.group(2) is not None and matches.group(3) is not None:
if str(matches.group(2)) == '-':
modifier = -1 * int(matches.group(3))
else:
modifier = int(matches.group(3))
result = roll + ': '
rolls = []
for d in range(dice):
rolls.append(random.randint(1, 10))
rolls.sort()
rolls.reverse()
# highest single die method
method1 = rolls[0]
# highest set method
method2 = 0
rolling_sum = 0
for i, r in enumerate(rolls):
# if next roll is same as current, sum and continue, else see if sum is best so far
if i+1 < len(rolls) and rolls[i+1] == r:
if rolling_sum == 0:
rolling_sum = r
rolling_sum += r
else:
if rolling_sum > method2:
method2 = rolling_sum
rolling_sum = 0
# check for set in progress (e.g. lots of 1s)
if rolling_sum > method2:
method2 = rolling_sum
# straight method
method3 = 0
rolling_sum = 0
count = 0
for i, r in enumerate(rolls):
# if next roll is one less as current, sum and continue, else check len and see if sum is best so far
if i+1 < len(rolls) and rolls[i+1] == r-1:
if rolling_sum == 0:
rolling_sum = r
count += 1
rolling_sum += r-1
count += 1
else:
if count >= 3 and rolling_sum > method3:
method3 = rolling_sum
rolling_sum = 0
# check for straight in progress (e.g. straight ending in 1)
if count >= 3 and rolling_sum > method3:
method3 = rolling_sum
# get best roll
best = max([method1, method2, method3])
# check for critical failure
botch = False
ones = 0
for r in rolls:
if r == 1:
ones += 1
if ones >= math.ceil(float(len(rolls))/2):
botch = True
if botch:
result += 'BOTCH'
else:
result += str(best + modifier)
rollres = ''
for i,r in enumerate(rolls):
rollres += str(r)
if i is not len(rolls)-1:
rollres += ','
result += ' [' + rollres
if modifier != 0:
if modifier > 0:
result += ' +' + str(modifier)
else:
result += ' -' + str(modifier * -1)
result += ']'
reply += result
if count is not len(rollitrs)-1:
reply += "; "
if reply is not "":
msg = "{0:s}: {1:s}".format(nick, reply)
return self.bot.reply(event, msg)
class DiceRoller(object):
tokens = ['NUMBER', 'TEXT', 'ROLLSEP']
literals = ['#', '/', '+', '-', 'd']
t_TEXT = r'\s+[^;]+'
t_ROLLSEP = r';\s*'
def build(self):
lex.lex(module=self)
yacc.yacc(module=self)
def t_NUMBER(self, t):
r'\d+'
t.value = int(t.value)
return t
def t_error(self, t):
t.lexer.skip(1)
precedence = (
('left', 'ROLLSEP'),
('left', '+', '-'),
('right', 'd'),
('left', '#'),
('left', '/')
)
output = ""
def roll_dice(self, keep, dice, size):
"""Takes the parsed dice string for a single roll (eg 3/4d20) and performs
the actual roll. Returns a string representing the result.
"""
a = list(range(dice))
for i in range(dice):
a[i] = random.randint(1, size)
if keep != dice:
b = sorted(a, reverse=True)
b = b[0:keep]
else:
b = a
total = sum(b)
outstr = "[" + ",".join(str(i) for i in a) + "]"
return (total, outstr)
def process_roll(self, trials, mods, comment):
"""Processes rolls coming from the parser.
This generates the inputs for the roll_dice() command, and returns
the full string representing the whole current dice string (the part
up to a semicolon or end of line).
"""
output = ""
repeat = 1
if trials != None:
repeat = trials
for i in range(repeat):
mode = 1
total = 0
curr_str = ""
if i > 0:
output += ", "
for m in mods:
keep = 0
dice = 1
res = 0
# if m is a tuple, then it is a die roll
# m[0] = (keep, num dice)
# m[1] = num faces on the die
if type(m) == tuple:
if m[0] != None:
if m[0][0] != None:
keep = m[0][0]
dice = m[0][1]
size = m[1]
if keep > dice or keep == 0:
keep = dice
if size < 1:
output = "# of sides for die is incorrect: %d" % size
return output
if dice < 1:
output = "# of dice is incorrect: %d" % dice
return output
res = self.roll_dice(keep, dice, size)
curr_str += "%d%s" % (res[0], res[1])
res = res[0]
elif m == "+":
mode = 1
curr_str += "+"
elif m == "-":
mode = -1
curr_str += "-"
else:
res = m
curr_str += str(m)
total += mode * res
if repeat == 1:
if comment != None:
output = "%d %s (%s)" % (total, comment.strip(), curr_str)
else:
output = "%d (%s)" % (total, curr_str)
else:
output += "%d (%s)" % (total, curr_str)
if i == repeat - 1:
if comment != None:
output += " (%s)" % (comment.strip())
return output
def p_roll_r(self, p):
# Chain rolls together.
# General idea I had when creating this grammar: A roll string is a chain
# of modifiers, which may be repeated for a certain number of trials. It can
# have a comment that describes the roll
# Multiple roll strings can be chained with semicolon
'roll : roll ROLLSEP roll'
global output
p[0] = p[1] + "; " + p[3]
output = p[0]
def p_roll(self, p):
# Parse a basic roll string.
'roll : trial modifier comment'
global output
mods = []
if type(p[2]) == list:
mods = p[2]
else:
mods = [p[2]]
p[0] = self.process_roll(p[1], mods, p[3])
output = p[0]
def p_roll_no_trials(self, p):
# Parse a roll string without trials.
'roll : modifier comment'
global output
mods = []
if type(p[1]) == list:
mods = p[1]
else:
mods = [p[1]]
p[0] = self.process_roll(None, mods, p[2])
output = p[0]
def p_comment(self, p):
# Parse a comment.
'''comment : TEXT
|'''
if len(p) == 2:
p[0] = p[1]
else:
p[0] = None
def p_modifier(self, p):
# Parse a modifier on a roll string.
'''modifier : modifier "+" modifier
| modifier "-" modifier'''
# Use append to prevent nested lists (makes dealing with this easier)
if type(p[1]) == list:
p[1].append(p[2])
p[1].append(p[3])
p[0] = p[1]
elif type(p[3]) == list:
p[3].insert(0, p[2])
p[3].insert(0, p[1])
p[0] = p[3]
else:
p[0] = [p[1], p[2], p[3]]
def p_die(self, p):
# Return the left side before the "d", and the number of faces.
'modifier : left NUMBER'
p[0] = (p[1], p[2])
def p_die_num(self, p):
'modifier : NUMBER'
p[0] = p[1]
def p_left(self, p):
# Parse the number of dice we are rolling, and how many we are keeping.
'left : keep dice'
if p[1] == None:
p[0] = [None, p[2]]
else:
p[0] = [p[1], p[2]]
def p_left_all(self, p):
'left : dice'
p[0] = [None, p[1]]
def p_left_e(self, p):
'left :'
p[0] = None
def p_total(self, p):
'trial : NUMBER "#"'
if len(p) > 1:
p[0] = p[1]
else:
p[0] = None
def p_keep(self, p):
'keep : NUMBER "/"'
if p[1] != None:
p[0] = p[1]
else:
p[0] = None
def p_dice(self, p):
'dice : NUMBER "d"'
p[0] = p[1]
def p_dice_one(self, p):
'dice : "d"'
p[0] = 1
def p_error(self, p):
# Provide the user with something (albeit not much) when the roll can't be parsed.
global output
output = "Unable to parse roll"
def get_result(self):
global output
return output
def do_roll(self, dicestr):
"""
Roll some dice and get the result (with broken out rolls).
Keyword arguments:
dicestr - format:
N#X/YdS+M label
N#: do the following roll N times (optional)
X/: take the top X rolls of the Y times rolled (optional)
Y : roll the die specified Y times (optional, defaults to 1)
dS: roll a S-sided die
+M: add M to the result (-M for subtraction) (optional)
"""
self.build()
yacc.parse(dicestr)
return self.get_result()
plugin = Dice plugin = Dice

View File

@ -1,263 +0,0 @@
"""Dice rollers used by the views, bots, etc."""
import logging
import random
import ply.lex as lex
import ply.yacc as yacc
logger = logging.getLogger(__name__)
class DiceRoller(object):
tokens = ['NUMBER', 'TEXT', 'ROLLSEP']
literals = ['#', '/', '+', '-', 'd']
t_TEXT = r'\s+[^;]+'
t_ROLLSEP = r';\s*'
def build(self):
lex.lex(module=self)
yacc.yacc(module=self)
def t_NUMBER(self, t):
r'\d+'
t.value = int(t.value)
return t
def t_error(self, t):
t.lexer.skip(1)
precedence = (
('left', 'ROLLSEP'),
('left', '+', '-'),
('right', 'd'),
('left', '#'),
('left', '/')
)
output = ""
def roll_dice(self, keep, dice, size):
"""Takes the parsed dice string for a single roll (eg 3/4d20) and performs
the actual roll. Returns a string representing the result.
"""
a = list(range(dice))
for i in range(dice):
a[i] = random.randint(1, size)
if keep != dice:
b = sorted(a, reverse=True)
b = b[0:keep]
else:
b = a
total = sum(b)
outstr = "[" + ",".join(str(i) for i in a) + "]"
return (total, outstr)
def process_roll(self, trials, mods, comment):
"""Processes rolls coming from the parser.
This generates the inputs for the roll_dice() command, and returns
the full string representing the whole current dice string (the part
up to a semicolon or end of line).
"""
rolls = mods[0][0][1] if mods[0][0][1] else 1
assert trials <= 10, "Too many rolls (max: 10)."
assert rolls <= 50, "Too many dice (max: 50) in roll."
output = ""
repeat = 1
if trials != None:
repeat = trials
for i in range(repeat):
mode = 1
total = 0
curr_str = ""
if i > 0:
output += ", "
for m in mods:
keep = 0
dice = 1
res = 0
# if m is a tuple, then it is a die roll
# m[0] = (keep, num dice)
# m[1] = num faces on the die
if type(m) == tuple:
if m[0] != None:
if m[0][0] != None:
keep = m[0][0]
dice = m[0][1]
size = m[1]
if keep > dice or keep == 0:
keep = dice
if size < 1:
output = "# of sides for die is incorrect: %d" % size
return output
if dice < 1:
output = "# of dice is incorrect: %d" % dice
return output
res = self.roll_dice(keep, dice, size)
curr_str += "%d%s" % (res[0], res[1])
res = res[0]
elif m == "+":
mode = 1
curr_str += "+"
elif m == "-":
mode = -1
curr_str += "-"
else:
res = m
curr_str += str(m)
total += mode * res
if repeat == 1:
if comment != None:
output = "%d %s (%s)" % (total, comment.strip(), curr_str)
else:
output = "%d (%s)" % (total, curr_str)
else:
output += "%d (%s)" % (total, curr_str)
if i == repeat - 1:
if comment != None:
output += " (%s)" % (comment.strip())
return output
def p_roll_r(self, p):
# Chain rolls together.
# General idea I had when creating this grammar: A roll string is a chain
# of modifiers, which may be repeated for a certain number of trials. It can
# have a comment that describes the roll
# Multiple roll strings can be chained with semicolon
'roll : roll ROLLSEP roll'
global output
p[0] = p[1] + "; " + p[3]
output = p[0]
def p_roll(self, p):
# Parse a basic roll string.
'roll : trial modifier comment'
global output
mods = []
if type(p[2]) == list:
mods = p[2]
else:
mods = [p[2]]
p[0] = self.process_roll(p[1], mods, p[3])
output = p[0]
def p_roll_no_trials(self, p):
# Parse a roll string without trials.
'roll : modifier comment'
global output
mods = []
if type(p[1]) == list:
mods = p[1]
else:
mods = [p[1]]
p[0] = self.process_roll(None, mods, p[2])
output = p[0]
def p_comment(self, p):
# Parse a comment.
'''comment : TEXT
|'''
if len(p) == 2:
p[0] = p[1]
else:
p[0] = None
def p_modifier(self, p):
# Parse a modifier on a roll string.
'''modifier : modifier "+" modifier
| modifier "-" modifier'''
# Use append to prevent nested lists (makes dealing with this easier)
if type(p[1]) == list:
p[1].append(p[2])
p[1].append(p[3])
p[0] = p[1]
elif type(p[3]) == list:
p[3].insert(0, p[2])
p[3].insert(0, p[1])
p[0] = p[3]
else:
p[0] = [p[1], p[2], p[3]]
def p_die(self, p):
# Return the left side before the "d", and the number of faces.
'modifier : left NUMBER'
p[0] = (p[1], p[2])
def p_die_num(self, p):
'modifier : NUMBER'
p[0] = p[1]
def p_left(self, p):
# Parse the number of dice we are rolling, and how many we are keeping.
'left : keep dice'
if p[1] == None:
p[0] = [None, p[2]]
else:
p[0] = [p[1], p[2]]
def p_left_all(self, p):
'left : dice'
p[0] = [None, p[1]]
def p_left_e(self, p):
'left :'
p[0] = None
def p_total(self, p):
'trial : NUMBER "#"'
if len(p) > 1:
p[0] = p[1]
else:
p[0] = None
def p_keep(self, p):
'keep : NUMBER "/"'
if p[1] != None:
p[0] = p[1]
else:
p[0] = None
def p_dice(self, p):
'dice : NUMBER "d"'
p[0] = p[1]
def p_dice_one(self, p):
'dice : "d"'
p[0] = 1
def p_error(self, p):
"""Raise ValueError on unparseable strings."""
raise ValueError("Error occurred in parser")
def get_result(self):
global output
return output
def do_roll(self, dicestr):
"""
Roll some dice and get the result (with broken out rolls).
Keyword arguments:
dicestr - format:
N#X/YdS+M label
N#: do the following roll N times (optional)
X/: take the top X rolls of the Y times rolled (optional)
Y : roll the die specified Y times (optional, defaults to 1)
dS: roll a S-sided die
+M: add M to the result (-M for subtraction) (optional)
"""
self.build()
yacc.parse(dicestr)
return self.get_result()

View File

@ -29,6 +29,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='dispatcheraction', model_name='dispatcheraction',
name='dispatcher', name='dispatcher',
field=models.ForeignKey(to='dispatch.Dispatcher', on_delete=models.CASCADE), field=models.ForeignKey(to='dispatch.Dispatcher'),
), ),
] ]

View File

@ -17,6 +17,6 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='dispatcheraction', model_name='dispatcheraction',
name='dispatcher', name='dispatcher',
field=models.ForeignKey(related_name='actions', to='dispatch.Dispatcher', on_delete=models.CASCADE), field=models.ForeignKey(related_name='actions', to='dispatch.Dispatcher'),
), ),
] ]

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -36,7 +36,7 @@ class DispatcherAction(models.Model):
(FILE_TYPE, "Write to file"), (FILE_TYPE, "Write to file"),
) )
dispatcher = models.ForeignKey('Dispatcher', related_name='actions', on_delete=models.CASCADE) dispatcher = models.ForeignKey('Dispatcher', related_name='actions')
type = models.CharField(max_length=16, choices=TYPE_CHOICES) type = models.CharField(max_length=16, choices=TYPE_CHOICES)
destination = models.CharField(max_length=200) destination = models.CharField(max_length=200)
include_key = models.BooleanField(default=False) include_key = models.BooleanField(default=False)

View File

@ -11,7 +11,7 @@ https://docs.djangoproject.com/en/1.6/ref/settings/
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os import os
from django.urls import reverse_lazy from django.core.urlresolvers import reverse_lazy
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) BASE_DIR = os.path.dirname(os.path.dirname(__file__))
@ -57,11 +57,12 @@ INSTALLED_APPS = (
'twitter', 'twitter',
) )
MIDDLEWARE = ( MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',

View File

@ -20,5 +20,5 @@ urlpatterns = [
url(r'^races/', include('races.urls')), url(r'^races/', include('races.urls')),
url(r'^accounts/', include('registration.backends.default.urls')), url(r'^accounts/', include('registration.backends.default.urls')),
url(r'^admin/', admin.site.urls), url(r'^admin/', include(admin.site.urls)),
] ]

View File

@ -26,6 +26,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='fact', model_name='fact',
name='category', name='category',
field=models.ForeignKey(to='facts.FactCategory', on_delete=models.CASCADE), field=models.ForeignKey(to='facts.FactCategory'),
), ),
] ]

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-02-11 15:00 # Generated by Django 1.10.5 on 2017-02-11 15:00
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -52,7 +52,7 @@ class Fact(models.Model):
"""Define facts.""" """Define facts."""
fact = models.TextField() fact = models.TextField()
category = models.ForeignKey(FactCategory, on_delete=models.CASCADE) category = models.ForeignKey(FactCategory)
nickmask = models.CharField(max_length=200, default='', blank=True) nickmask = models.CharField(max_length=200, default='', blank=True)
time = models.DateTimeField(auto_now_add=True) time = models.DateTimeField(auto_now_add=True)

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -25,7 +27,7 @@ class Migration(migrations.Migration):
('code_reviews_necessary', models.PositiveSmallIntegerField(default=0)), ('code_reviews_necessary', models.PositiveSmallIntegerField(default=0)),
('code_reviewers', models.TextField(blank=True, default='')), ('code_reviewers', models.TextField(blank=True, default='')),
('code_review_final_merge_assignees', models.TextField(blank=True, default='')), ('code_review_final_merge_assignees', models.TextField(blank=True, default='')),
('gitlab_config', models.ForeignKey(to='gitlab_bot.GitlabConfig', null=True, on_delete=models.CASCADE)), ('gitlab_config', models.ForeignKey(to='gitlab_bot.GitlabConfig', null=True)),
], ],
), ),
] ]

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -23,7 +23,7 @@ class GitlabProjectConfig(models.Model):
"""Maintain settings for a particular project in GitLab.""" """Maintain settings for a particular project in GitLab."""
gitlab_config = models.ForeignKey('GitlabConfig', null=True, on_delete=models.CASCADE) gitlab_config = models.ForeignKey('GitlabConfig', null=True)
project_id = models.CharField(max_length=64, unique=True) project_id = models.CharField(max_length=64, unique=True)
manage_merge_request_code_reviews = models.BooleanField(default=False) manage_merge_request_code_reviews = models.BooleanField(default=False)

View File

@ -15,7 +15,7 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='botadmin', model_name='botadmin',
name='user', name='user',
field=models.ForeignKey(default=1, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE), field=models.ForeignKey(default=1, to=settings.AUTH_USER_MODEL),
preserve_default=False, preserve_default=False,
), ),
] ]

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -47,7 +47,7 @@ class BotUser(models.Model):
"""Configure bot users, which can do things through the bot and standard Django auth.""" """Configure bot users, which can do things through the bot and standard Django auth."""
nickmask = models.CharField(max_length=200, unique=True) nickmask = models.CharField(max_length=200, unique=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Meta: class Meta:
permissions = ( permissions = (

View File

@ -23,7 +23,7 @@ class Migration(migrations.Migration):
('delta', models.SmallIntegerField()), ('delta', models.SmallIntegerField()),
('nickmask', models.CharField(default='', max_length=200, blank=True)), ('nickmask', models.CharField(default='', max_length=200, blank=True)),
('created', models.DateTimeField(auto_now_add=True)), ('created', models.DateTimeField(auto_now_add=True)),
('key', models.ForeignKey(to='karma.KarmaKey', on_delete=models.CASCADE)), ('key', models.ForeignKey(to='karma.KarmaKey')),
], ],
), ),
] ]

View File

@ -115,7 +115,7 @@ class KarmaLogEntryManager(models.Manager):
class KarmaLogEntry(models.Model): class KarmaLogEntry(models.Model):
"""Track each karma increment/decrement.""" """Track each karma increment/decrement."""
key = models.ForeignKey('KarmaKey', on_delete=models.CASCADE) key = models.ForeignKey('KarmaKey')
delta = models.SmallIntegerField() delta = models.SmallIntegerField()
nickmask = models.CharField(max_length=200, default='', blank=True) nickmask = models.CharField(max_length=200, default='', blank=True)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)

View File

@ -27,7 +27,7 @@ class Migration(migrations.Migration):
('k2', models.CharField(max_length=128)), ('k2', models.CharField(max_length=128)),
('v', models.CharField(max_length=128)), ('v', models.CharField(max_length=128)),
('count', models.IntegerField(default=0)), ('count', models.IntegerField(default=0)),
('context', models.ForeignKey(to='markov.MarkovContext', on_delete=models.CASCADE)), ('context', models.ForeignKey(to='markov.MarkovContext')),
], ],
options={ options={
'permissions': set([('teach_line', 'Can teach lines'), ('import_log_file', 'Can import states from a log file')]), 'permissions': set([('teach_line', 'Can teach lines'), ('import_log_file', 'Can import states from a log file')]),
@ -40,7 +40,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(unique=True, max_length=64)), ('name', models.CharField(unique=True, max_length=64)),
('chatter_chance', models.IntegerField(default=0)), ('chatter_chance', models.IntegerField(default=0)),
('context', models.ForeignKey(to='markov.MarkovContext', on_delete=models.CASCADE)), ('context', models.ForeignKey(to='markov.MarkovContext')),
], ],
options={ options={
}, },

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -28,7 +28,7 @@ class MarkovTarget(models.Model):
"""Define IRC targets that relate to a context, and can occasionally be talked to.""" """Define IRC targets that relate to a context, and can occasionally be talked to."""
name = models.CharField(max_length=200, unique=True) name = models.CharField(max_length=200, unique=True)
context = models.ForeignKey(MarkovContext, on_delete=models.CASCADE) context = models.ForeignKey(MarkovContext)
chatter_chance = models.IntegerField(default=0) chatter_chance = models.IntegerField(default=0)
@ -51,7 +51,7 @@ class MarkovState(models.Model):
v = models.CharField(max_length=128) v = models.CharField(max_length=128)
count = models.IntegerField(default=0) count = models.IntegerField(default=0)
context = models.ForeignKey(MarkovContext, on_delete=models.CASCADE) context = models.ForeignKey(MarkovContext)
class Meta: class Meta:
index_together = [ index_together = [

View File

@ -29,7 +29,7 @@ class Migration(migrations.Migration):
('joined', models.BooleanField(default=False)), ('joined', models.BooleanField(default=False)),
('started', models.BooleanField(default=False)), ('started', models.BooleanField(default=False)),
('finished', models.BooleanField(default=False)), ('finished', models.BooleanField(default=False)),
('race', models.ForeignKey(to='races.Race', on_delete=models.CASCADE)), ('race', models.ForeignKey(to='races.Race')),
], ],
options={ options={
}, },
@ -41,8 +41,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('update', models.TextField()), ('update', models.TextField()),
('event_time', models.DateTimeField(default=django.utils.timezone.now)), ('event_time', models.DateTimeField(default=django.utils.timezone.now)),
('race', models.ForeignKey(to='races.Race', on_delete=models.CASCADE)), ('race', models.ForeignKey(to='races.Race')),
('racer', models.ForeignKey(to='races.Racer', on_delete=models.CASCADE)), ('racer', models.ForeignKey(to='races.Racer')),
], ],
options={ options={
'ordering': ['event_time'], 'ordering': ['event_time'],

View File

@ -28,7 +28,7 @@ class Racer(models.Model):
"""Track a racer in a race.""" """Track a racer in a race."""
nick = models.CharField(max_length=64) nick = models.CharField(max_length=64)
race = models.ForeignKey(Race, on_delete=models.CASCADE) race = models.ForeignKey(Race)
joined = models.BooleanField(default=False) joined = models.BooleanField(default=False)
started = models.BooleanField(default=False) started = models.BooleanField(default=False)
@ -47,8 +47,8 @@ class RaceUpdate(models.Model):
"""Periodic updates for a racer.""" """Periodic updates for a racer."""
race = models.ForeignKey(Race, on_delete=models.CASCADE) race = models.ForeignKey(Race)
racer = models.ForeignKey(Racer, on_delete=models.CASCADE) racer = models.ForeignKey(Racer)
update = models.TextField() update = models.TextField()
event_time = models.DateTimeField(default=timezone.now) event_time = models.DateTimeField(default=timezone.now)

View File

@ -2,68 +2,64 @@
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile
# To update, run: # To update, run:
# #
# pip-compile --output-file=requirements-dev.txt requirements-dev.in # pip-compile --output-file requirements-dev.txt requirements-dev.in
# #
astroid==2.2.5 # via pylint, pylint-celery, pylint-flask, requirements-detector appdirs==1.4.0 # via setuptools
certifi==2019.6.16 # via requests astroid==1.4.9 # via pylint, pylint-celery, pylint-flask, pylint-plugin-utils, requirements-detector
chardet==3.0.4 # via requests click==6.7 # via pip-tools
click==7.0 # via pip-tools
django-adminplus==0.5 django-adminplus==0.5
django-bootstrap3==11.0.0 django-bootstrap3==8.1.0
django-extensions==2.1.9 django-extensions==1.7.6
django-registration-redux==2.6 django-registration-redux==1.4
django==2.2.2 django==1.10.5
djangorestframework==3.9.4 djangorestframework==3.5.3
dodgy==0.1.9 # via prospector dodgy==0.1.9 # via prospector
future==0.17.1 # via parsedatetime first==2.0.1 # via pip-tools
idna==2.8 # via requests future==0.16.0 # via parsedatetime
importlib-metadata==0.18 # via irc inflect==0.2.5 # via jaraco.itertools
inflect==2.1.0 # via jaraco.itertools irc==15.0.6
irc==17.1 isort==4.2.5 # via pylint
isort==4.3.20 # via pylint jaraco.classes==1.4 # via jaraco.collections
jaraco.classes==2.0 # via jaraco.collections jaraco.collections==1.5 # via irc, jaraco.text
jaraco.collections==2.0 # via irc jaraco.functools==1.15.1 # via irc, jaraco.text
jaraco.functools==2.0 # via irc, jaraco.text, tempora jaraco.itertools==2.0 # via irc
jaraco.itertools==4.4.2 # via irc jaraco.logging==1.5 # via irc
jaraco.logging==2.0 # via irc jaraco.stream==1.1.1 # via irc
jaraco.stream==2.0 # via irc jaraco.text==1.9 # via irc, jaraco.collections
jaraco.text==3.0 # via irc, jaraco.collections lazy-object-proxy==1.2.2 # via astroid
lazy-object-proxy==1.4.1 # via astroid logilab-common==1.3.0
logilab-common==1.4.2
mccabe==0.6.1 # via prospector, pylint mccabe==0.6.1 # via prospector, pylint
more-itertools==7.0.0 # via irc, jaraco.functools, jaraco.itertools more-itertools==2.5.0 # via irc, jaraco.functools, jaraco.itertools
oauthlib==3.0.1 # via requests-oauthlib oauthlib==2.0.1 # via requests-oauthlib
parsedatetime==2.4 packaging==16.8 # via setuptools
parsedatetime==2.2
pep8-naming==0.4.1 # via prospector pep8-naming==0.4.1 # via prospector
pip-tools==3.8.0 pip-tools==1.8.0
ply==3.11 ply==3.10
prospector==1.1.6.4 prospector==0.12.4
pycodestyle==2.4.0 # via prospector pycodestyle==2.0.0 # via prospector
pydocstyle==3.0.0 # via prospector pydocstyle==1.0.0 # via prospector
pyflakes==1.6.0 # via prospector pyflakes==1.5.0 # via prospector
pylint-celery==0.3 # via prospector pylint-celery==0.3 # via prospector
pylint-django==2.0.9 # via prospector pylint-common==0.2.2 # via prospector
pylint-flask==0.6 # via prospector pylint-django==0.7.2 # via prospector
pylint-plugin-utils==0.5 # via prospector, pylint-celery, pylint-django, pylint-flask pylint-flask==0.5 # via prospector
pylint==2.3.1 # via prospector, pylint-celery, pylint-django, pylint-flask, pylint-plugin-utils pylint-plugin-utils==0.2.4 # via prospector, pylint-celery, pylint-django, pylint-flask
python-dateutil==2.8.0 pylint==1.6.5 # via prospector, pylint-celery, pylint-common, pylint-django, pylint-flask, pylint-plugin-utils
python-gitlab==1.9.0 pyparsing==2.1.10 # via packaging
python-mpd2==1.0.0 python-dateutil==2.6.0
pytz==2019.1 python-gitlab==0.18
pyyaml==5.1.1 # via prospector python-mpd2==0.5.5
requests-oauthlib==1.2.0 # via twython pytz==2016.10
requests==2.22.0 # via python-gitlab, requests-oauthlib, twython pyyaml==3.12 # via prospector
requirements-detector==0.6 # via prospector requests-oauthlib==0.7.0 # via twython
requests==2.13.0 # via python-gitlab, requests-oauthlib, twython
requirements-detector==0.5.2 # via prospector
setoptconf==0.2.0 # via prospector setoptconf==0.2.0 # via prospector
six==1.12.0 # via astroid, django-extensions, jaraco.classes, jaraco.collections, jaraco.itertools, jaraco.logging, jaraco.stream, logilab-common, pip-tools, pydocstyle, python-dateutil, python-gitlab, tempora six==1.10.0 # via astroid, django-extensions, irc, jaraco.classes, jaraco.collections, jaraco.itertools, jaraco.logging, jaraco.stream, logilab-common, more-itertools, packaging, pip-tools, pylint, python-dateutil, python-gitlab, setuptools, tempora
snowballstemmer==1.2.1 # via pydocstyle tempora==1.6.1 # via irc, jaraco.logging
sqlparse==0.3.0 # via django twython==3.4.0
tempora==1.14.1 # via irc, jaraco.logging wrapt==1.10.8 # via astroid
twython==3.7.0
typed-ast==1.4.0 # via astroid
urllib3==1.25.3 # via requests
wrapt==1.11.2 # via astroid
zipp==0.5.1 # via importlib-metadata
# The following packages are considered to be unsafe in a requirements file: # The following packages are considered to be unsafe in a requirements file:
# setuptools==41.0.1 # via logilab-common # setuptools # via logilab-common

3
requirements-server.in Normal file
View File

@ -0,0 +1,3 @@
-r requirements.in
psycopg2

36
requirements-server.txt Normal file
View File

@ -0,0 +1,36 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile --output-file requirements-server.txt requirements-server.in
#
django-adminplus==0.5
django-bootstrap3==8.1.0
django-extensions==1.7.6
django-registration-redux==1.4
django==1.10.5
djangorestframework==3.5.3
future==0.16.0 # via parsedatetime
inflect==0.2.5 # via jaraco.itertools
irc==15.0.6
jaraco.classes==1.4 # via jaraco.collections
jaraco.collections==1.5 # via irc, jaraco.text
jaraco.functools==1.15.1 # via irc, jaraco.text
jaraco.itertools==2.0 # via irc
jaraco.logging==1.5 # via irc
jaraco.stream==1.1.1 # via irc
jaraco.text==1.9 # via irc, jaraco.collections
more-itertools==2.5.0 # via irc, jaraco.functools, jaraco.itertools
oauthlib==2.0.1 # via requests-oauthlib
parsedatetime==2.2
ply==3.10
psycopg2==2.6.2
python-dateutil==2.6.0
python-gitlab==0.18
python-mpd2==0.5.5
pytz==2016.10
requests-oauthlib==0.7.0 # via twython
requests==2.13.0 # via python-gitlab, requests-oauthlib, twython
six==1.10.0 # via django-extensions, irc, jaraco.classes, jaraco.collections, jaraco.itertools, jaraco.logging, jaraco.stream, more-itertools, python-dateutil, python-gitlab, tempora
tempora==1.6.1 # via irc, jaraco.logging
twython==3.4.0

View File

@ -2,41 +2,34 @@
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile
# To update, run: # To update, run:
# #
# pip-compile --output-file=requirements.txt requirements.in # pip-compile --output-file requirements.txt requirements.in
# #
certifi==2019.6.16 # via requests
chardet==3.0.4 # via requests
django-adminplus==0.5 django-adminplus==0.5
django-bootstrap3==11.0.0 django-bootstrap3==8.1.0
django-extensions==2.1.9 django-extensions==1.7.6
django-registration-redux==2.6 django-registration-redux==1.4
django==2.2.2 django==1.10.5
djangorestframework==3.9.4 djangorestframework==3.5.3
future==0.17.1 # via parsedatetime future==0.16.0 # via parsedatetime
idna==2.8 # via requests inflect==0.2.5 # via jaraco.itertools
importlib-metadata==0.18 # via irc irc==15.0.6
inflect==2.1.0 # via jaraco.itertools jaraco.classes==1.4 # via jaraco.collections
irc==17.1 jaraco.collections==1.5 # via irc, jaraco.text
jaraco.classes==2.0 # via jaraco.collections jaraco.functools==1.15.1 # via irc, jaraco.text
jaraco.collections==2.0 # via irc jaraco.itertools==2.0 # via irc
jaraco.functools==2.0 # via irc, jaraco.text, tempora jaraco.logging==1.5 # via irc
jaraco.itertools==4.4.2 # via irc jaraco.stream==1.1.1 # via irc
jaraco.logging==2.0 # via irc jaraco.text==1.9 # via irc, jaraco.collections
jaraco.stream==2.0 # via irc more-itertools==2.5.0 # via irc, jaraco.functools, jaraco.itertools
jaraco.text==3.0 # via irc, jaraco.collections oauthlib==2.0.1 # via requests-oauthlib
more-itertools==7.0.0 # via irc, jaraco.functools, jaraco.itertools parsedatetime==2.2
oauthlib==3.0.1 # via requests-oauthlib ply==3.10
parsedatetime==2.4 python-dateutil==2.6.0
ply==3.11 python-gitlab==0.18
python-dateutil==2.8.0 python-mpd2==0.5.5
python-gitlab==1.9.0 pytz==2016.10
python-mpd2==1.0.0 requests-oauthlib==0.7.0 # via twython
pytz==2019.1 requests==2.13.0 # via python-gitlab, requests-oauthlib, twython
requests-oauthlib==1.2.0 # via twython six==1.10.0 # via django-extensions, irc, jaraco.classes, jaraco.collections, jaraco.itertools, jaraco.logging, jaraco.stream, more-itertools, python-dateutil, python-gitlab, tempora
requests==2.22.0 # via python-gitlab, requests-oauthlib, twython tempora==1.6.1 # via irc, jaraco.logging
six==1.12.0 # via django-extensions, jaraco.classes, jaraco.collections, jaraco.itertools, jaraco.logging, jaraco.stream, python-dateutil, python-gitlab, tempora twython==3.4.0
sqlparse==0.3.0 # via django
tempora==1.14.1 # via irc, jaraco.logging
twython==3.7.0
urllib3==1.25.3 # via requests
zipp==0.5.1 # via importlib-metadata

View File

@ -1,4 +1,7 @@
"""Use dr.botzo's Dispatch to send mpd notifications.""" """Use dr.botzo's Dispatch to send mpd notifications."""
from __future__ import unicode_literals
import argparse import argparse
import getpass import getpass
import logging import logging

View File

@ -29,7 +29,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('line', models.TextField(default='')), ('line', models.TextField(default='')),
('time', models.DateTimeField(auto_now_add=True)), ('time', models.DateTimeField(auto_now_add=True)),
('game', models.ForeignKey(to='storycraft.StorycraftGame', on_delete=models.CASCADE)), ('game', models.ForeignKey(to='storycraft.StorycraftGame')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -38,12 +38,12 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('nick', models.CharField(max_length=64)), ('nick', models.CharField(max_length=64)),
('nickmask', models.CharField(max_length=200)), ('nickmask', models.CharField(max_length=200)),
('game', models.ForeignKey(to='storycraft.StorycraftGame', on_delete=models.CASCADE)), ('game', models.ForeignKey(to='storycraft.StorycraftGame')),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='storycraftline', model_name='storycraftline',
name='player', name='player',
field=models.ForeignKey(to='storycraft.StorycraftPlayer', on_delete=models.CASCADE), field=models.ForeignKey(to='storycraft.StorycraftPlayer'),
), ),
] ]

View File

@ -13,16 +13,16 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='storycraftline', model_name='storycraftline',
name='game', name='game',
field=models.ForeignKey(related_name='lines', to='storycraft.StorycraftGame', on_delete=models.CASCADE), field=models.ForeignKey(related_name='lines', to='storycraft.StorycraftGame'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='storycraftline', model_name='storycraftline',
name='player', name='player',
field=models.ForeignKey(related_name='lines', to='storycraft.StorycraftPlayer', on_delete=models.CASCADE), field=models.ForeignKey(related_name='lines', to='storycraft.StorycraftPlayer'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='storycraftplayer', model_name='storycraftplayer',
name='game', name='game',
field=models.ForeignKey(related_name='players', to='storycraft.StorycraftGame', on_delete=models.CASCADE), field=models.ForeignKey(related_name='players', to='storycraft.StorycraftGame'),
), ),
] ]

View File

@ -89,7 +89,7 @@ class StorycraftPlayer(models.Model):
"""Contain entire games of storycraft.""" """Contain entire games of storycraft."""
game = models.ForeignKey('StorycraftGame', related_name='players', on_delete=models.CASCADE) game = models.ForeignKey('StorycraftGame', related_name='players')
nick = models.CharField(max_length=64) nick = models.CharField(max_length=64)
nickmask = models.CharField(max_length=200) nickmask = models.CharField(max_length=200)
@ -103,8 +103,8 @@ class StorycraftLine(models.Model):
"""Handle requests to dispatchers and do something with them.""" """Handle requests to dispatchers and do something with them."""
game = models.ForeignKey('StorycraftGame', related_name='lines', on_delete=models.CASCADE) game = models.ForeignKey('StorycraftGame', related_name='lines')
player = models.ForeignKey('StorycraftPlayer', related_name='lines', on_delete=models.CASCADE) player = models.ForeignKey('StorycraftPlayer', related_name='lines')
line = models.TextField(default="") line = models.TextField(default="")
time = models.DateTimeField(auto_now_add=True) time = models.DateTimeField(auto_now_add=True)

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -17,6 +19,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='twitterclient', model_name='twitterclient',
name='mentions_output_channel', name='mentions_output_channel',
field=models.ForeignKey(blank=True, related_name='mentions_twitter_client', null=True, to='ircbot.IrcChannel', default=None, on_delete=models.CASCADE), field=models.ForeignKey(blank=True, related_name='mentions_twitter_client', null=True, to='ircbot.IrcChannel', default=None),
), ),
] ]

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -18,7 +18,7 @@ class TwitterClient(models.Model):
oauth_token_secret = models.CharField(max_length=256, default='', blank=True) oauth_token_secret = models.CharField(max_length=256, default='', blank=True)
mentions_output_channel = models.ForeignKey(IrcChannel, related_name='mentions_twitter_client', default=None, mentions_output_channel = models.ForeignKey(IrcChannel, related_name='mentions_twitter_client', default=None,
null=True, blank=True, on_delete=models.CASCADE) null=True, blank=True)
mentions_since_id = models.PositiveIntegerField(default=1, blank=True) mentions_since_id = models.PositiveIntegerField(default=1, blank=True)
class Meta: class Meta: