Files
2026-07-29 10:47:40 +00:00

74 lines
2.3 KiB
Python

from django.db import models
from django.contrib.auth.models import User
class StudentProfile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE
)
xp = models.IntegerField(default=0)
streak = models.IntegerField(default=0)
last_activity_date = models.DateField(null=True, blank=True)
daily_goal = models.IntegerField(default=60)
target_band = models.FloatField(default=7.5)
display_name = models.CharField(max_length=40, blank=True)
country = models.CharField(max_length=80, blank=True)
def __str__(self):
return self.user.username
class PremiumEntitlement(models.Model):
SOURCE_ADMIN = "admin"
SOURCE_PAYMENT = "payment"
SOURCE_PROMOTION = "promotion"
SOURCE_CHOICES = [
(SOURCE_ADMIN, "Admin grant"),
(SOURCE_PAYMENT, "One-time payment"),
(SOURCE_PROMOTION, "Promotion"),
]
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
related_name="premium_entitlement",
)
source = models.CharField(max_length=20, choices=SOURCE_CHOICES, default=SOURCE_ADMIN)
order_reference = models.CharField(max_length=120, blank=True)
granted_at = models.DateTimeField(auto_now_add=True)
revoked_at = models.DateTimeField(null=True, blank=True)
notes = models.TextField(blank=True)
@property
def is_active(self):
return self.revoked_at is None
def __str__(self):
state = "active" if self.is_active else "revoked"
return f"{self.user} · Lifetime Premium ({state})"
class DailyMissionClaim(models.Model):
"""Records one XP reward per student, mission, and calendar day."""
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="daily_mission_claims")
mission_key = models.CharField(max_length=40)
completed_on = models.DateField()
xp_awarded = models.PositiveIntegerField()
claimed_at = models.DateTimeField(auto_now_add=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["user", "mission_key", "completed_on"],
name="unique_daily_mission_claim",
),
]
ordering = ["-completed_on", "-claimed_at"]
def __str__(self):
return f"{self.user} · {self.mission_key} · {self.completed_on}"