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:
+111
-28
@@ -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."
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user