dr.botzo/karma/models.py
Brian S. Stephan cc9b110531
fix a display issue in the karma key score
this would probably only matter if adding a key manually that doesn't
have a score, but a fix is a fix

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
2025-02-08 23:57:23 -06:00

136 lines
4.7 KiB
Python

"""Karma logging models."""
import logging
from datetime import timedelta
import pytz
from django.conf import settings
from django.db import models
from django.utils import timezone
from irc.client import NickMask
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):
"""Display the karma key and score."""
return "{0:s} ({1:d})".format(self.key, self.score())
def score(self):
"""Determine the score for this karma entry."""
score = KarmaLogEntry.objects.filter(key=self).aggregate(models.Sum('delta'))['delta__sum']
return score if score else 0
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)