Time tracker app
This commit is contained in:
@@ -15,6 +15,7 @@ from app.models import (
|
||||
from app.schemas import (
|
||||
SpinResult, AssignmentResponse, CompleteResult, DropResult,
|
||||
GameResponse, ChallengeResponse, GameShort, UserPublic, MessageResponse,
|
||||
TrackTimeRequest,
|
||||
)
|
||||
from app.schemas.game import PlaythroughInfo
|
||||
from app.services.points import PointsService
|
||||
@@ -589,7 +590,14 @@ async def complete_assignment(
|
||||
if assignment.is_playthrough:
|
||||
game = assignment.game
|
||||
marathon_id = game.marathon_id
|
||||
base_playthrough_points = game.playthrough_points
|
||||
|
||||
# If tracked time exists (from desktop app), calculate points as hours * 30
|
||||
# Otherwise use admin-set playthrough_points
|
||||
if assignment.tracked_time_minutes > 0:
|
||||
hours = assignment.tracked_time_minutes / 60
|
||||
base_playthrough_points = int(hours * 30)
|
||||
else:
|
||||
base_playthrough_points = game.playthrough_points
|
||||
|
||||
# Calculate BASE bonus points from completed bonus assignments (before multiplier)
|
||||
base_bonus_points = sum(
|
||||
@@ -850,6 +858,37 @@ async def complete_assignment(
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/assignments/{assignment_id}/track-time", response_model=MessageResponse)
|
||||
async def track_assignment_time(
|
||||
assignment_id: int,
|
||||
data: TrackTimeRequest,
|
||||
current_user: CurrentUser,
|
||||
db: DbSession,
|
||||
):
|
||||
"""Update tracked time for an assignment (from desktop app)"""
|
||||
result = await db.execute(
|
||||
select(Assignment)
|
||||
.options(selectinload(Assignment.participant))
|
||||
.where(Assignment.id == assignment_id)
|
||||
)
|
||||
assignment = result.scalar_one_or_none()
|
||||
|
||||
if not assignment:
|
||||
raise HTTPException(status_code=404, detail="Assignment not found")
|
||||
|
||||
if assignment.participant.user_id != current_user.id:
|
||||
raise HTTPException(status_code=403, detail="This is not your assignment")
|
||||
|
||||
if assignment.status != AssignmentStatus.ACTIVE.value:
|
||||
raise HTTPException(status_code=400, detail="Assignment is not active")
|
||||
|
||||
# Update tracked time (replace with new value)
|
||||
assignment.tracked_time_minutes = max(0, data.minutes)
|
||||
await db.commit()
|
||||
|
||||
return MessageResponse(message=f"Tracked time updated to {data.minutes} minutes")
|
||||
|
||||
|
||||
@router.post("/assignments/{assignment_id}/drop", response_model=DropResult)
|
||||
async def drop_assignment(assignment_id: int, current_user: CurrentUser, db: DbSession):
|
||||
"""Drop current assignment"""
|
||||
|
||||
@@ -60,7 +60,12 @@ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
||||
# CORS
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:3000", "http://127.0.0.1:3000"],
|
||||
allow_origins=[
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000",
|
||||
"http://localhost:5173", # Desktop app dev
|
||||
"http://127.0.0.1:5173",
|
||||
],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
|
||||
@@ -32,6 +32,7 @@ class Assignment(Base):
|
||||
proof_comment: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
points_earned: Mapped[int] = mapped_column(Integer, default=0)
|
||||
streak_at_completion: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
tracked_time_minutes: Mapped[int] = mapped_column(Integer, default=0) # Time tracked by desktop app
|
||||
started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ from app.schemas.assignment import (
|
||||
CompleteBonusAssignment,
|
||||
BonusCompleteResult,
|
||||
AvailableGamesCount,
|
||||
TrackTimeRequest,
|
||||
)
|
||||
from app.schemas.activity import (
|
||||
ActivityResponse,
|
||||
|
||||
@@ -52,6 +52,7 @@ class AssignmentResponse(BaseModel):
|
||||
proof_comment: str | None = None
|
||||
points_earned: int
|
||||
streak_at_completion: int | None = None
|
||||
tracked_time_minutes: int = 0 # Time tracked by desktop app
|
||||
started_at: datetime
|
||||
completed_at: datetime | None = None
|
||||
drop_penalty: int = 0 # Calculated penalty if dropped
|
||||
@@ -62,6 +63,11 @@ class AssignmentResponse(BaseModel):
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class TrackTimeRequest(BaseModel):
|
||||
"""Request to update tracked time for an assignment"""
|
||||
minutes: int # Total minutes tracked (replaces previous value)
|
||||
|
||||
|
||||
class SpinResult(BaseModel):
|
||||
assignment_id: int
|
||||
game: GameResponse
|
||||
|
||||
Reference in New Issue
Block a user