This commit is contained in:
2026-01-05 07:15:50 +07:00
parent 65b2512d8c
commit 6a7717a474
44 changed files with 5678 additions and 183 deletions

View File

@@ -1,6 +1,6 @@
from datetime import datetime
from enum import Enum
from sqlalchemy import DateTime, ForeignKey, Integer, String, UniqueConstraint
from sqlalchemy import DateTime, ForeignKey, Integer, String, UniqueConstraint, Boolean, Float
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
@@ -26,6 +26,15 @@ class Participant(Base):
drop_count: Mapped[int] = mapped_column(Integer, default=0) # For progressive penalty
joined_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
# Shop: coins earned in this marathon
coins_earned: Mapped[int] = mapped_column(Integer, default=0)
# Shop: consumables state
skips_used: Mapped[int] = mapped_column(Integer, default=0)
active_boost_multiplier: Mapped[float | None] = mapped_column(Float, nullable=True)
active_boost_expires_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
has_shield: Mapped[bool] = mapped_column(Boolean, default=False)
# Relationships
user: Mapped["User"] = relationship("User", back_populates="participations")
marathon: Mapped["Marathon"] = relationship("Marathon", back_populates="participants")
@@ -38,3 +47,16 @@ class Participant(Base):
@property
def is_organizer(self) -> bool:
return self.role == ParticipantRole.ORGANIZER.value
@property
def has_active_boost(self) -> bool:
"""Check if participant has an active boost"""
if self.active_boost_multiplier is None or self.active_boost_expires_at is None:
return False
return datetime.utcnow() < self.active_boost_expires_at
def get_boost_multiplier(self) -> float:
"""Get current boost multiplier (1.0 if no active boost)"""
if self.has_active_boost:
return self.active_boost_multiplier or 1.0
return 1.0