feat: implement Story 4.1 - Access Registration Page

Allows potential participants to view exchange details and access
the registration form via unique slug URLs.

Implementation:
- Added ParticipantRegistrationForm with name, email, gift_ideas, and reminder fields
- Created GET /exchange/<slug>/register route
- Built responsive registration template with exchange details
- Exempted participant routes from admin setup requirement
- Comprehensive test coverage for all scenarios

Acceptance Criteria Met:
- Valid slug displays registration form with exchange details
- Invalid slug returns 404
- Form includes all required fields with CSRF protection
- Registration deadline is displayed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-22 17:05:09 -07:00
parent abed4ac84a
commit 81e2cb8c86
6 changed files with 294 additions and 7 deletions

View File

@@ -1,13 +1,17 @@
"""Participant routes for Sneaky Klaus application."""
from flask import Blueprint
from flask import Blueprint, abort, render_template
from src.app import db
from src.forms.participant import ParticipantRegistrationForm
from src.models.exchange import Exchange
participant_bp = Blueprint("participant", __name__, url_prefix="")
@participant_bp.route("/exchange/<slug>/register")
def register(slug):
"""Participant registration page (stub for now).
@participant_bp.route("/exchange/<slug>/register", methods=["GET", "POST"])
def register(slug: str):
"""Participant registration page.
Args:
slug: Exchange registration slug.
@@ -15,4 +19,16 @@ def register(slug):
Returns:
Rendered registration page template.
"""
return f"Registration page for exchange: {slug}"
# Find the exchange by slug
exchange = db.session.query(Exchange).filter_by(slug=slug).first()
if not exchange:
abort(404)
# Create the registration form
form = ParticipantRegistrationForm()
return render_template(
"participant/register.html",
exchange=exchange,
form=form,
)