Files
gh-christianlouis-leagueledger/app/views/redeem.py
T
Christian Krakau-Louis 0de2eb5830 Implement user authentication and management system with FastAPI
- Added authentication routes for login, registration, password reset, and account deletion in `auth.py`.
- Implemented user profile management, including updating user information and changing passwords.
- Created dashboard views to display user-specific information and recent activity in `dashboard.py`.
- Developed leaderboard views to show team rankings and points in `leaderboard.py`.
- Added QR code generation and redemption functionality in `qr.py` and `redeem.py`.
- Implemented team management features, allowing users to create and join teams in `teams.py`.
- Introduced session debugging utility to assist with session-related issues in `debug_session.py`.
- Configured Docker Compose for MySQL database and FastAPI application with environment variables.
- Updated requirements.txt to include necessary dependencies for the application.
2025-04-11 17:46:59 +02:00

157 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""
Redeem a QR code and attribute points to a team.
"""
from fastapi import APIRouter, Depends, Request, Form, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy.orm import Session
from ..db import SessionLocal
from ..models import QRTicket, User, Team, TeamMembership
from ..templates_config import templates
router = APIRouter()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@router.get("/{code}", response_class=HTMLResponse)
def redeem_code(code: str, request: Request, db: Session = Depends(get_db)):
"""
Display a page to let the user choose which team to apply points to.
If not logged in, prompt them.
"""
# In real app, you'd check user session or redirect to login
ticket = db.query(QRTicket).filter_by(code=code, used=False).first()
if not ticket:
return "Invalid or already used code."
# Skeleton: you'd get the user's teams from session user
# For now, we mock a user ID = 1:
user = db.query(User).filter_by(id=1).first()
if not user:
return "User not found. Please log in."
# This is where you'd show the team selection or "create new team" UI
user_teams = [m.team for m in user.memberships]
return templates.TemplateResponse("redeem.html", {
"request": request,
"ticket": ticket,
"user_teams": user_teams
})
@router.post("/apply/{code}")
async def apply_code(
request: Request,
code: str,
db: Session = Depends(get_db)
):
"""
Apply the QR code to a selected team (if user is a member),
or set to pending if user isn't a member yet.
"""
# Get form data
form_data = await request.form()
team_id = int(form_data.get("team_id", 0))
if team_id <= 0:
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Team Selection Required",
"error_message": "Please select a team to redeem this code."
}
)
ticket = db.query(QRTicket).filter_by(code=code, used=False).first()
if not ticket:
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Invalid Code",
"error_message": "This code is invalid or has already been used."
}
)
# For skeleton, assume user = 1
user = db.query(User).filter_by(id=1).first()
team = db.query(Team).filter_by(id=team_id).first()
if not team:
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Team Not Found",
"error_message": "The selected team could not be found."
}
)
# Check membership
membership = db.query(TeamMembership).filter_by(user_id=user.id, team_id=team.id).first()
if membership:
# Redeem
ticket.redeemed_by = user.id
ticket.redeemed_at_team = team.id
ticket.used = True
# If we have redeemed_at column, update it
if hasattr(ticket, 'redeemed_at'):
from datetime import datetime
ticket.redeemed_at = datetime.now()
db.commit()
# Redirect to success page or dashboard
return templates.TemplateResponse(
"redeem_success.html",
{
"request": request,
"points": ticket.points,
"team": team
}
)
else:
# In real app, create a pending record or request flow
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Not a Team Member",
"error_message": "You are not a member of this team. Please join the team first or select another team."
}
)
@router.post("/manual")
async def manual_code_entry(
request: Request,
code: str = Form(...),
db: Session = Depends(get_db)
):
"""
Handle manual code entry from the form.
This redirects to the normal redeem flow after validating the code.
"""
# Check if the code exists
ticket = db.query(QRTicket).filter_by(code=code, used=False).first()
if not ticket:
# In a real app, add a flash message or error handling
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Invalid Code",
"error_message": "The code you entered is invalid or has already been used."
}
)
# Redirect to the regular redeem flow
return RedirectResponse(f"/redeem/{code}", status_code=303)