cqtu/contest/models.py

175 lines
5.1 KiB
Python

from __future__ import unicode_literals
import datetime
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.core.validators import RegexValidator
from django.db.models import Q
from .validators import CallUsernameValidator
class Contest(models.Model):
name = models.CharField(max_length=20)
shortName = models.CharField(max_length=20, unique=True)
callQrg = models.ForeignKey("Frequency", models.SET_NULL, null=True, blank=True)
deadline = models.DateTimeField()
def __str__(self):
return self.name
class Reference(models.Model):
name = models.CharField(max_length=20, unique=True, db_index=True)
description = models.TextField()
def __str__(self):
return self.name
class EntryCategory(models.Model):
name = models.CharField(max_length=64, unique=True)
description = models.TextField(blank=True)
def __str__(self):
return self.name
class ShadowCall(models.Model):
username = models.CharField(max_length=20, unique=True, db_index=True, validators=[CallUsernameValidator()])
ref = models.ForeignKey(Reference, models.SET_NULL,null=True, blank=True)
def __str__(self):
return self.username
class User(AbstractUser):
ref = models.ForeignKey(Reference, models.SET_NULL, null=True, blank=True)
cat = models.ForeignKey(EntryCategory, models.SET_NULL, null=True, blank=True)
def __init__(self, *args, **kwargs):
super(User, self).__init__(*args, **kwargs)
self._meta.get_field("username").validators = [CallUsernameValidator()]
def getQSOCount(self):
return self.qso_set.count()
def getCfmdQSOCount(self):
return self.qso_set.filter(~Q(cfmdQSO=None)).count()
def getCfmdRefCount(self):
return len(set(map(lambda _x: _x["refStr"], self.qso_set.filter(ref__isnull=False).values("ref", "refStr"))))
class Band(models.Model):
name = models.CharField(max_length=10)
contest = models.ForeignKey(Contest)
def __str__(self):
return self.name
class Frequency(models.Model):
# qrg
# band
channel = models.CharField(max_length=3)
qrg = models.DecimalField(max_digits=7, decimal_places=3)
band = models.ForeignKey(Band)
note = models.CharField(max_length=50, blank=True)
def __str__(self):
return "Channel %s: %s MHz" % (self.channel, self.qrg)
class QSO(models.Model):
reportValidator = RegexValidator("[1-5][1-9]")
class Meta:
index_together = [
["owner", "call"],
]
owner = models.ForeignKey(User, db_index=True)
time = models.DateTimeField(blank=True)
call = models.CharField(max_length=20, db_index=True)
callRef = models.ForeignKey(User, models.SET_NULL, related_name='qsoref', null=True, blank=True, default=None)
band = models.ForeignKey(Band)
reportTX = models.CharField(max_length=7, default=59, verbose_name='RST-S', validators=[reportValidator])
reportRX = models.CharField(max_length=7, default=59, verbose_name='RST-R', validators=[reportValidator])
ownNo = models.IntegerField(verbose_name='No-S')
otherNo = models.IntegerField(verbose_name='No-R', null=True, blank=True)
refStr = models.CharField(max_length=20, verbose_name="EXC")
ref = models.ForeignKey(Reference, models.SET_NULL, null=True, blank=True)
remarks = models.CharField(max_length=50, blank=True, default=None)
cfmdQSO = models.ForeignKey("QSO", models.SET_NULL, null=True, blank=True, default=None)
CFMD_SEC = 300
def checkQSOData(self):
""" Match strdata to log rows. Only call, if you intent to save this object if we return True! """
# find reference
changed = False
if self.refStr:
# Old reference exists?
if self.ref and self.ref.name != self.refStr:
self.ref = None
changed = True
if not self.ref:
# find matching ref
try:
self.ref = Reference.objects.get(name=self.refStr)
changed = True
except Reference.DoesNotExist:
pass
# find call
if not self.callRef or self.callRef.username != self.call:
try:
self.callRef = User.objects.get(username=self.call)
changed = True
except User.DoesNotExist:
if self.callRef:
changed = True
self.callRef = None
# find matching qso
if self.cfmdQSO:
# check if this still checks out
q = self.cfmdQSO
if (self.time - q.time).total_seconds() <= self.CFMD_SEC and \
self.ref and self.owner.ref and \
self.ref == q.owner.ref and self.owner.ref == q.ref and \
self.band == q.band:
# checks out
pass
else:
changed = True
self.cfmdQSO.cfmdQSO = None
self.cfmdQSO = None
self.cfmdQSO = None
if self.ref and self.callRef and self.callRef.ref and not self.cfmdQSO:
# look for a matching line
q = QSO.objects.filter(
(Q(time__gte=self.time + datetime.timedelta(0, self.CFMD_SEC)) | Q(time__gte=self.time - datetime.timedelta(0, self.CFMD_SEC))),
owner__ref=self.ref,
ref=self.owner.ref,
band=self.band)
if q.count() == 1:
changed = True
q[0].cfmdQSO = self
q[0].save(checkQSO=False)
self.cfmdQSO = q[0]
return changed
def save(self, checkQSO=True, *args, **kwargs):
if checkQSO:
self.checkQSOData()
super(QSO, self).save(*args, **kwargs)
def __str__(self):
return "QSO no %s at from %s %s with %s@%s %s/%s" % (self.ownNo, self.time.strftime("%H:%M"), self.owner.username, self.call, self.refStr, self.reportTX, self.reportRX)