dr.botzo/karma/models.py

136 lines
4.6 KiB
Python

"""Karma logging models."""
from datetime import timedelta
import logging
import pytz
from irc.client import NickMask
from django.conf import settings
from django.db import models
from django.utils import timezone
log = logging.getLogger('karma.models')
def perdelta(start, end, delta):
"""Return karma between two dates."""
curr = start
while curr < end:
yield curr
curr += delta
yield end
class KarmaKeyManager(models.Manager):
"""Manage handy queries for KarmaKey."""
def ranked_scored_order(self):
"""Provide karma keys in rank order, with numbered position."""
keys = self.annotate(karma_score=models.Sum('karmalogentry__delta')).order_by('-karma_score')
return keys
def ranked_scored_reverse_order(self):
"""Provide karma keys in reverse rank order, with numbered position."""
keys = self.annotate(karma_score=models.Sum('karmalogentry__delta')).order_by('karma_score')
return keys
class KarmaKey(models.Model):
"""Track a thing being karmaed."""
key = models.CharField(max_length=200, unique=True)
objects = KarmaKeyManager()
def __str__(self):
"""String representation."""
return "{0:s} ({1:d})".format(self.key, self.score())
def score(self):
"""Determine the score for this karma entry."""
return KarmaLogEntry.objects.filter(key=self).aggregate(models.Sum('delta'))['delta__sum']
def rank(self):
"""Determine the rank of this karma entry relative to the others."""
sorted_keys = KarmaKey.objects.ranked_scored_order()
for rank, key in enumerate(sorted_keys):
if key == self:
return rank + 1
return None
def history(self, mode='delta'):
"""Determine the score for this karma entry at every delta."""
history = []
if mode == 'delta':
entries = KarmaLogEntry.objects.filter(key=self).order_by('created')
for entry in entries:
timestamp = entry.created
delta = entry.delta
score = KarmaLogEntry.objects.filter(key=self).filter(created__lte=entry.created).aggregate(
models.Sum('delta'))['delta__sum']
history.append((timestamp, delta, score))
elif mode == 'date':
first_entry = KarmaLogEntry.objects.filter(key=self).order_by('created')[0]
slice_begin = first_entry.created.date()
slice_end = timezone.now().date()
for timeslice in perdelta(slice_begin, slice_end, timedelta(days=1)):
score = KarmaLogEntry.objects.filter(key=self).filter(
created__lte=timeslice + timedelta(days=1)).aggregate(models.Sum('delta'))['delta__sum']
if not score:
score = 0
try:
prev_score = history[-1][2]
except IndexError:
prev_score = 0
delta = score - prev_score
history.append((timeslice, delta, score))
return history
class KarmaLogEntryManager(models.Manager):
"""Manage handy queries for KarmaLogEntry."""
def optimists(self):
"""Return karma users who gave the most positive karma."""
karmaers = self.values('nickmask').annotate(karma_outlook=models.Sum('delta')).order_by('-karma_outlook')
return karmaers
def pessimists(self):
"""Return karma users who gave the most negative karma."""
karmaers = self.values('nickmask').annotate(karma_outlook=models.Sum('delta')).order_by('karma_outlook')
return karmaers
def most_opinionated(self):
"""Return karma users who gave the most karma."""
karmaers = self.values('nickmask').annotate(karma_count=models.Count('delta')).order_by('-karma_count')
return karmaers
class KarmaLogEntry(models.Model):
"""Track each karma increment/decrement."""
key = models.ForeignKey('KarmaKey', on_delete=models.CASCADE)
delta = models.SmallIntegerField()
nickmask = models.CharField(max_length=200, default='', blank=True)
created = models.DateTimeField(auto_now_add=True)
objects = KarmaLogEntryManager()
class Meta:
"""Meta options."""
verbose_name_plural = 'karma log entries'
def __str__(self):
"""String representation."""
tz = pytz.timezone(settings.TIME_ZONE)
return "{0:s}{1:s} @ {2:s} by {3:s}".format(self.key.key, '++' if self.delta > 0 else '--',
self.created.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S %Z'),
NickMask(self.nickmask).nick)