Add Impressum and QR code management templates

- Created a new Impressum page with legal information and contact details.
- Developed admin link page for linking QR codes to events with form functionality.
- Implemented QR code dashboard for managing QR code sets, including creation and quick actions.
- Added detailed view for QR code sets, allowing addition of QR codes and management actions.
- Introduced static file serving for favicon and related images.
- Established views for static content pages (about, contact, privacy, terms).
- Implemented translation management scripts for compiling and updating translations.
This commit is contained in:
Christian Krakau-Louis
2025-04-14 03:19:41 +02:00
parent 9eef726d9b
commit d595b468e9
43 changed files with 2895 additions and 391 deletions
+111 -28
View File
@@ -2,15 +2,20 @@
"""
Redeem a QR code and attribute points to a team.
"""
import os
from fastapi import APIRouter, Depends, Request, Form, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy.orm import Session
from datetime import datetime
from ..db import SessionLocal
from ..models import QRTicket, User, Team, TeamMembership
from ..models import QRCode, User, Team, TeamMembership, TeamAchievement
from ..templates_config import templates
router = APIRouter()
# Get base URL from environment variable or use default
BASE_URL = os.environ.get("LEAGUELEDGER_BASE_URL", "https://rover.leagueledger.net")
def get_db():
db = SessionLocal()
try:
@@ -24,14 +29,38 @@ 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.
No login required.
"""
ticket = db.query(QRTicket).filter_by(code=code, used=False).first()
if not ticket:
# Find the QR code record
qr_code = db.query(QRCode).filter_by(code=code).first()
# Handle invalid or already used codes
if not qr_code:
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Invalid Code",
"error_message": "This code is invalid or has already been used."
"error_message": "This QR code is invalid or does not exist."
}
)
if qr_code.used and (not qr_code.max_uses or qr_code.max_uses <= 1):
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Code Already Used",
"error_message": "This QR code has already been redeemed."
}
)
# Check expiration if applicable
if qr_code.expires_at and qr_code.expires_at < datetime.now():
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Expired Code",
"error_message": "This QR code has expired and can no longer be redeemed."
}
)
@@ -40,8 +69,19 @@ def redeem_code(code: str, request: Request, db: Session = Depends(get_db)):
return templates.TemplateResponse("redeem.html", {
"request": request,
"ticket": ticket,
"user_teams": all_teams # Now showing all teams
"ticket": qr_code, # Using the same template variable name for compatibility
"user_teams": all_teams,
"has_achievement": bool(qr_code.achievement_name),
"base_url": BASE_URL
})
@router.get("/scan", response_class=HTMLResponse)
def scan_qr_code(request: Request):
"""
Display the QR code scanner page
"""
return templates.TemplateResponse("scan_qr.html", {
"request": request
})
@router.post("/apply/{code}")
@@ -51,7 +91,7 @@ async def apply_code(
db: Session = Depends(get_db)
):
"""
Apply the QR code to a selected team (without authentication)
Apply the QR code to a selected team and award points and/or achievements
"""
# Get form data
form_data = await request.form()
@@ -67,19 +107,41 @@ async def apply_code(
}
)
ticket = db.query(QRTicket).filter_by(code=code, used=False).first()
if not ticket:
# Get the QR code
qr_code = db.query(QRCode).filter_by(code=code).first()
if not qr_code:
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Invalid Code",
"error_message": "This code is invalid or has already been used."
"error_message": "This QR code is invalid or does not exist."
}
)
# Check if the code is already used (for single-use codes)
if qr_code.used and (not qr_code.max_uses or qr_code.max_uses <= 1):
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Code Already Used",
"error_message": "This QR code has already been redeemed."
}
)
# Check expiration if applicable
if qr_code.expires_at and qr_code.expires_at < datetime.now():
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Expired Code",
"error_message": "This QR code has expired and can no longer be redeemed."
}
)
team = db.query(Team).filter_by(id=team_id).first()
if not team:
return templates.TemplateResponse(
"error.html",
@@ -90,24 +152,35 @@ async def apply_code(
}
)
# Redeem without checking membership
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()
# Mark the QR code as redeemed
qr_code.redeemed_at_team = team.id
qr_code.redeemed_at = datetime.now()
qr_code.used = True
# Handle achievements if present
if qr_code.achievement_name:
achievement = TeamAchievement(
team_id=team.id,
name=qr_code.achievement_name,
description=qr_code.description,
event_id=qr_code.event_id,
qr_code_id=qr_code.id,
achieved_at=datetime.now()
)
db.add(achievement)
db.commit()
# Redirect to success page or dashboard
# Return the success page with appropriate information
return templates.TemplateResponse(
"redeem_success.html",
{
"request": request,
"points": ticket.points,
"team": team
"points": qr_code.points,
"achievement": qr_code.achievement_name if qr_code.achievement_name else None,
"team": team,
"event": qr_code.event if qr_code.event else None,
"base_url": BASE_URL
}
)
@@ -122,16 +195,26 @@ async def manual_code_entry(
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()
qr_code = db.query(QRCode).filter_by(code=code).first()
if not ticket:
# In a real app, add a flash message or error handling
if not qr_code:
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Invalid Code",
"error_message": "The code you entered is invalid or has already been used."
"error_message": "The code you entered is invalid or does not exist."
}
)
# Check if already used (for single-use codes)
if qr_code.used and (not qr_code.max_uses or qr_code.max_uses <= 1):
return templates.TemplateResponse(
"error.html",
{
"request": request,
"error_title": "Code Already Used",
"error_message": "This code has already been redeemed."
}
)